1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * xenbus_dev.c 29 * 30 * Driver giving user-space access to the kernel's xenbus connection 31 * to xenstore. 32 * 33 * Copyright (c) 2005, Christian Limpach 34 * Copyright (c) 2005, Rusty Russell, IBM Corporation 35 * 36 * This file may be distributed separately from the Linux kernel, or 37 * incorporated into other software packages, subject to the following license: 38 * 39 * Permission is hereby granted, free of charge, to any person obtaining a copy 40 * of this source file (the "Software"), to deal in the Software without 41 * restriction, including without limitation the rights to use, copy, modify, 42 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 43 * and to permit persons to whom the Software is furnished to do so, subject to 44 * the following conditions: 45 * 46 * The above copyright notice and this permission notice shall be included in 47 * all copies or substantial portions of the Software. 48 * 49 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 54 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 55 * IN THE SOFTWARE. 56 */ 57 58 59 #include <sys/types.h> 60 #include <sys/sysmacros.h> 61 #include <sys/conf.h> 62 #include <sys/stat.h> 63 #include <sys/modctl.h> 64 #include <sys/uio.h> 65 #include <sys/list.h> 66 #include <sys/file.h> 67 #include <sys/errno.h> 68 #include <sys/open.h> 69 #include <sys/cred.h> 70 #include <sys/condvar.h> 71 #include <sys/ddi.h> 72 #include <sys/sunddi.h> 73 #include <sys/policy.h> 74 75 #ifdef XPV_HVM_DRIVER 76 #include <public/io/xenbus.h> 77 #include <public/io/xs_wire.h> 78 #include <sys/xpv_support.h> 79 #endif 80 #include <sys/hypervisor.h> 81 #include <xen/sys/xenbus.h> 82 #include <xen/sys/xenbus_comms.h> 83 #include <xen/sys/xenbus_impl.h> 84 #include <xen/public/io/xs_wire.h> 85 86 #ifdef DEBUG 87 #define XENBUSDRV_DBPRINT(fmt) { if (xenbusdrv_debug) cmn_err fmt; } 88 #else 89 #define XENBUSDRV_DBPRINT(fmt) 90 #endif /* ifdef DEBUG */ 91 92 /* Some handy macros */ 93 #define XENBUSDRV_MASK_READ_IDX(idx) ((idx) & (PAGESIZE - 1)) 94 #define XENBUSDRV_MINOR2INST(minor) ((int)(minor)) 95 #define XENBUSDRV_NCLONES 256 96 #define XENBUSDRV_INST2SOFTS(instance) \ 97 ((xenbus_dev_t *)ddi_get_soft_state(xenbusdrv_statep, (instance))) 98 99 static int xenbusdrv_debug = 0; 100 static int xenbusdrv_clone_tab[XENBUSDRV_NCLONES]; 101 static dev_info_t *xenbusdrv_dip; 102 static kmutex_t xenbusdrv_clone_tab_mutex; 103 104 struct xenbus_dev_transaction { 105 list_t list; 106 xenbus_transaction_t handle; 107 }; 108 109 /* Soft state data structure for xenbus driver */ 110 struct xenbus_dev_data { 111 dev_info_t *dip; 112 113 /* In-progress transaction. */ 114 list_t transactions; 115 116 /* Partial request. */ 117 unsigned int len; 118 union { 119 struct xsd_sockmsg msg; 120 char buffer[MMU_PAGESIZE]; 121 } u; 122 123 /* Response queue. */ 124 char read_buffer[MMU_PAGESIZE]; 125 unsigned int read_cons, read_prod; 126 kcondvar_t read_cv; 127 kmutex_t read_mutex; 128 int xenstore_inst; 129 }; 130 typedef struct xenbus_dev_data xenbus_dev_t; 131 static void *xenbusdrv_statep; 132 133 static int xenbusdrv_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 134 static int xenbusdrv_attach(dev_info_t *, ddi_attach_cmd_t); 135 static int xenbusdrv_detach(dev_info_t *, ddi_detach_cmd_t); 136 static int xenbusdrv_open(dev_t *, int, int, cred_t *); 137 static int xenbusdrv_close(dev_t, int, int, cred_t *); 138 static int xenbusdrv_read(dev_t, struct uio *, cred_t *); 139 static int xenbusdrv_write(dev_t, struct uio *, cred_t *); 140 static int xenbusdrv_devmap(dev_t, devmap_cookie_t, offset_t, size_t, size_t *, 141 uint_t); 142 static int xenbusdrv_segmap(dev_t, off_t, ddi_as_handle_t, caddr_t *, off_t, 143 uint_t, uint_t, uint_t, cred_t *); 144 static int xenbusdrv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 145 static int xenbusdrv_queue_reply(xenbus_dev_t *, const struct xsd_sockmsg *, 146 const char *); 147 148 /* Solaris driver framework */ 149 150 static struct cb_ops xenbusdrv_cb_ops = { 151 xenbusdrv_open, /* cb_open */ 152 xenbusdrv_close, /* cb_close */ 153 nodev, /* cb_strategy */ 154 nodev, /* cb_print */ 155 nodev, /* cb_dump */ 156 xenbusdrv_read, /* cb_read */ 157 xenbusdrv_write, /* cb_write */ 158 xenbusdrv_ioctl, /* cb_ioctl */ 159 xenbusdrv_devmap, /* cb_devmap */ 160 NULL, /* cb_mmap */ 161 xenbusdrv_segmap, /* cb_segmap */ 162 nochpoll, /* cb_chpoll */ 163 ddi_prop_op, /* cb_prop_op */ 164 0, /* cb_stream */ 165 D_DEVMAP | D_NEW | D_MP, /* cb_flag */ 166 CB_REV 167 }; 168 169 static struct dev_ops xenbusdrv_dev_ops = { 170 DEVO_REV, /* devo_rev */ 171 0, /* devo_refcnt */ 172 xenbusdrv_info, /* devo_getinfo */ 173 nulldev, /* devo_identify */ 174 nulldev, /* devo_probe */ 175 xenbusdrv_attach, /* devo_attach */ 176 xenbusdrv_detach, /* devo_detach */ 177 nodev, /* devo_reset */ 178 &xenbusdrv_cb_ops, /* devo_cb_ops */ 179 NULL, /* devo_bus_ops */ 180 NULL, /* devo_power */ 181 ddi_quiesce_not_needed, /* devo_quiesce */ 182 }; 183 184 static struct modldrv modldrv = { 185 &mod_driverops, /* Type of module. This one is a driver */ 186 "virtual bus driver", /* Name of the module. */ 187 &xenbusdrv_dev_ops /* driver ops */ 188 }; 189 190 static struct modlinkage modlinkage = { 191 MODREV_1, 192 &modldrv, 193 NULL 194 }; 195 196 int 197 _init(void) 198 { 199 int e; 200 201 e = ddi_soft_state_init(&xenbusdrv_statep, sizeof (xenbus_dev_t), 1); 202 if (e) 203 return (e); 204 205 e = mod_install(&modlinkage); 206 if (e) 207 ddi_soft_state_fini(&xenbusdrv_statep); 208 209 return (e); 210 } 211 212 int 213 _fini(void) 214 { 215 int e; 216 217 e = mod_remove(&modlinkage); 218 if (e) 219 return (e); 220 221 ddi_soft_state_fini(&xenbusdrv_statep); 222 223 return (0); 224 } 225 226 int 227 _info(struct modinfo *modinfop) 228 { 229 return (mod_info(&modlinkage, modinfop)); 230 } 231 232 /* ARGSUSED */ 233 static int 234 xenbusdrv_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 235 { 236 dev_t dev = (dev_t)arg; 237 minor_t minor = getminor(dev); 238 int retval; 239 240 switch (cmd) { 241 case DDI_INFO_DEVT2DEVINFO: 242 if (minor != 0 || xenbusdrv_dip == NULL) { 243 *result = (void *)NULL; 244 retval = DDI_FAILURE; 245 } else { 246 *result = (void *)xenbusdrv_dip; 247 retval = DDI_SUCCESS; 248 } 249 break; 250 case DDI_INFO_DEVT2INSTANCE: 251 *result = (void *)0; 252 retval = DDI_SUCCESS; 253 break; 254 default: 255 retval = DDI_FAILURE; 256 } 257 return (retval); 258 } 259 260 static int 261 xenbusdrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 262 { 263 int error; 264 int unit = ddi_get_instance(dip); 265 266 267 switch (cmd) { 268 case DDI_ATTACH: 269 break; 270 case DDI_RESUME: 271 return (DDI_SUCCESS); 272 default: 273 cmn_err(CE_WARN, "xenbus_attach: unknown cmd 0x%x\n", cmd); 274 return (DDI_FAILURE); 275 } 276 277 /* DDI_ATTACH */ 278 279 /* 280 * only one instance - but we clone using the open routine 281 */ 282 if (ddi_get_instance(dip) > 0) 283 return (DDI_FAILURE); 284 285 mutex_init(&xenbusdrv_clone_tab_mutex, NULL, MUTEX_DRIVER, 286 NULL); 287 288 error = ddi_create_minor_node(dip, "xenbus", S_IFCHR, unit, 289 DDI_PSEUDO, NULL); 290 if (error != DDI_SUCCESS) 291 goto fail; 292 293 /* 294 * save dip for getinfo 295 */ 296 xenbusdrv_dip = dip; 297 ddi_report_dev(dip); 298 299 #ifndef XPV_HVM_DRIVER 300 if (DOMAIN_IS_INITDOMAIN(xen_info)) 301 xs_dom0_init(); 302 #endif 303 304 return (DDI_SUCCESS); 305 306 fail: 307 (void) xenbusdrv_detach(dip, DDI_DETACH); 308 return (error); 309 } 310 311 static int 312 xenbusdrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 313 { 314 /* 315 * again, only one instance 316 */ 317 if (ddi_get_instance(dip) > 0) 318 return (DDI_FAILURE); 319 320 switch (cmd) { 321 case DDI_DETACH: 322 ddi_remove_minor_node(dip, NULL); 323 mutex_destroy(&xenbusdrv_clone_tab_mutex); 324 xenbusdrv_dip = NULL; 325 return (DDI_SUCCESS); 326 case DDI_SUSPEND: 327 return (DDI_SUCCESS); 328 default: 329 cmn_err(CE_WARN, "xenbus_detach: unknown cmd 0x%x\n", cmd); 330 return (DDI_FAILURE); 331 } 332 } 333 334 /* ARGSUSED */ 335 static int 336 xenbusdrv_open(dev_t *devp, int flag, int otyp, cred_t *cr) 337 { 338 xenbus_dev_t *xbs; 339 minor_t minor = getminor(*devp); 340 341 if (otyp == OTYP_BLK) 342 return (ENXIO); 343 344 /* 345 * only allow open on minor = 0 - the clone device 346 */ 347 if (minor != 0) 348 return (ENXIO); 349 350 /* 351 * find a free slot and grab it 352 */ 353 mutex_enter(&xenbusdrv_clone_tab_mutex); 354 for (minor = 1; minor < XENBUSDRV_NCLONES; minor++) { 355 if (xenbusdrv_clone_tab[minor] == 0) { 356 xenbusdrv_clone_tab[minor] = 1; 357 break; 358 } 359 } 360 mutex_exit(&xenbusdrv_clone_tab_mutex); 361 if (minor == XENBUSDRV_NCLONES) 362 return (EAGAIN); 363 364 /* Allocate softstate structure */ 365 if (ddi_soft_state_zalloc(xenbusdrv_statep, 366 XENBUSDRV_MINOR2INST(minor)) != DDI_SUCCESS) { 367 mutex_enter(&xenbusdrv_clone_tab_mutex); 368 xenbusdrv_clone_tab[minor] = 0; 369 mutex_exit(&xenbusdrv_clone_tab_mutex); 370 return (EAGAIN); 371 } 372 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor)); 373 374 /* ... and init it */ 375 xbs->dip = xenbusdrv_dip; 376 mutex_init(&xbs->read_mutex, NULL, MUTEX_DRIVER, NULL); 377 cv_init(&xbs->read_cv, NULL, CV_DEFAULT, NULL); 378 list_create(&xbs->transactions, sizeof (struct xenbus_dev_transaction), 379 offsetof(struct xenbus_dev_transaction, list)); 380 381 /* clone driver */ 382 *devp = makedevice(getmajor(*devp), minor); 383 XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv open succeeded, minor=%d", 384 minor)); 385 386 return (0); 387 } 388 389 /* ARGSUSED */ 390 static int 391 xenbusdrv_close(dev_t dev, int flag, int otyp, struct cred *cr) 392 { 393 xenbus_dev_t *xbs; 394 minor_t minor = getminor(dev); 395 struct xenbus_dev_transaction *trans; 396 397 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor)); 398 if (xbs == NULL) 399 return (ENXIO); 400 401 #ifdef notyet 402 /* 403 * XXPV - would like to be able to notify xenstore down here, but 404 * as the daemon is currently written, it doesn't leave the device 405 * open after initial setup, so we have no way of knowing if it has 406 * gone away. 407 */ 408 if (xbs->xenstore_inst) 409 xs_notify_xenstore_down(); 410 #endif 411 /* free pending transaction */ 412 while (trans = (struct xenbus_dev_transaction *) 413 list_head(&xbs->transactions)) { 414 (void) xenbus_transaction_end(trans->handle, 1); 415 list_remove(&xbs->transactions, (void *)trans); 416 kmem_free(trans, sizeof (*trans)); 417 } 418 419 mutex_destroy(&xbs->read_mutex); 420 cv_destroy(&xbs->read_cv); 421 ddi_soft_state_free(xenbusdrv_statep, XENBUSDRV_MINOR2INST(minor)); 422 423 /* 424 * free clone tab slot 425 */ 426 mutex_enter(&xenbusdrv_clone_tab_mutex); 427 xenbusdrv_clone_tab[minor] = 0; 428 mutex_exit(&xenbusdrv_clone_tab_mutex); 429 430 XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv close succeeded, minor=%d", 431 minor)); 432 433 return (0); 434 } 435 436 /* ARGSUSED */ 437 static int 438 xenbusdrv_read(dev_t dev, struct uio *uiop, cred_t *cr) 439 { 440 xenbus_dev_t *xbs; 441 size_t len; 442 int res, ret; 443 int idx; 444 445 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_read called")); 446 447 if (secpolicy_xvm_control(cr)) 448 return (EPERM); 449 450 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 451 452 mutex_enter(&xbs->read_mutex); 453 454 /* check if we have something to read */ 455 while (xbs->read_prod == xbs->read_cons) { 456 if (cv_wait_sig(&xbs->read_cv, &xbs->read_mutex) == 0) { 457 mutex_exit(&xbs->read_mutex); 458 return (EINTR); 459 } 460 } 461 462 idx = XENBUSDRV_MASK_READ_IDX(xbs->read_cons); 463 res = uiop->uio_resid; 464 465 len = xbs->read_prod - xbs->read_cons; 466 467 if (len > (sizeof (xbs->read_buffer) - idx)) 468 len = sizeof (xbs->read_buffer) - idx; 469 if (len > res) 470 len = res; 471 472 ret = uiomove(xbs->read_buffer + idx, len, UIO_READ, uiop); 473 xbs->read_cons += res - uiop->uio_resid; 474 mutex_exit(&xbs->read_mutex); 475 476 return (ret); 477 } 478 479 /* 480 * prepare data for xenbusdrv_read() 481 */ 482 static int 483 xenbusdrv_queue_reply(xenbus_dev_t *xbs, const struct xsd_sockmsg *msg, 484 const char *reply) 485 { 486 int i; 487 int remaining; 488 489 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply called")); 490 491 mutex_enter(&xbs->read_mutex); 492 493 remaining = sizeof (xbs->read_buffer) - 494 (xbs->read_prod - xbs->read_cons); 495 496 if (sizeof (*msg) + msg->len > remaining) { 497 mutex_exit(&xbs->read_mutex); 498 return (EOVERFLOW); 499 } 500 501 for (i = 0; i < sizeof (*msg); i++, xbs->read_prod++) { 502 xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] = 503 ((char *)msg)[i]; 504 } 505 506 for (i = 0; i < msg->len; i++, xbs->read_prod++) { 507 xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] = 508 reply[i]; 509 } 510 511 cv_broadcast(&xbs->read_cv); 512 513 mutex_exit(&xbs->read_mutex); 514 515 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply exited")); 516 517 return (0); 518 } 519 520 /* ARGSUSED */ 521 static int 522 xenbusdrv_write(dev_t dev, struct uio *uiop, cred_t *cr) 523 { 524 xenbus_dev_t *xbs; 525 struct xenbus_dev_transaction *trans; 526 void *reply; 527 size_t len; 528 int rc = 0; 529 530 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_write called")); 531 532 if (secpolicy_xvm_control(cr)) 533 return (EPERM); 534 535 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 536 len = uiop->uio_resid; 537 538 if ((len + xbs->len) > sizeof (xbs->u.buffer)) { 539 XENBUSDRV_DBPRINT((CE_WARN, "Request is too big")); 540 rc = EINVAL; 541 goto out; 542 } 543 544 if (uiomove(xbs->u.buffer + xbs->len, len, UIO_WRITE, uiop) != 0) { 545 XENBUSDRV_DBPRINT((CE_WARN, "Uiomove failed")); 546 rc = EFAULT; 547 goto out; 548 } 549 550 xbs->len += len; 551 552 if (xbs->len < (sizeof (xbs->u.msg)) || 553 xbs->len < (sizeof (xbs->u.msg) + xbs->u.msg.len)) { 554 XENBUSDRV_DBPRINT((CE_NOTE, "Partial request")); 555 return (0); 556 } 557 558 switch (xbs->u.msg.type) { 559 case XS_TRANSACTION_START: 560 case XS_TRANSACTION_END: 561 case XS_DIRECTORY: 562 case XS_READ: 563 case XS_GET_PERMS: 564 case XS_RELEASE: 565 case XS_GET_DOMAIN_PATH: 566 case XS_WRITE: 567 case XS_MKDIR: 568 case XS_RM: 569 case XS_SET_PERMS: 570 /* send the request to xenstore and get feedback */ 571 rc = xenbus_dev_request_and_reply(&xbs->u.msg, &reply); 572 if (rc) { 573 XENBUSDRV_DBPRINT((CE_WARN, 574 "xenbus_dev_request_and_reply failed")); 575 goto out; 576 } 577 578 /* handle transaction start/end */ 579 if (xbs->u.msg.type == XS_TRANSACTION_START) { 580 trans = kmem_alloc(sizeof (*trans), KM_SLEEP); 581 (void) ddi_strtoul((char *)reply, NULL, 0, 582 (unsigned long *)&trans->handle); 583 list_insert_tail(&xbs->transactions, (void *)trans); 584 } else if (xbs->u.msg.type == XS_TRANSACTION_END) { 585 /* try to find out the ending transaction */ 586 for (trans = (struct xenbus_dev_transaction *) 587 list_head(&xbs->transactions); trans; 588 trans = (struct xenbus_dev_transaction *) 589 list_next(&xbs->transactions, (void *)trans)) 590 if (trans->handle == 591 (xenbus_transaction_t) 592 xbs->u.msg.tx_id) 593 break; 594 ASSERT(trans); 595 /* free it, if we find it */ 596 list_remove(&xbs->transactions, (void *)trans); 597 kmem_free(trans, sizeof (*trans)); 598 } 599 600 /* prepare data for xenbusdrv_read() to get */ 601 rc = xenbusdrv_queue_reply(xbs, &xbs->u.msg, reply); 602 603 kmem_free(reply, xbs->u.msg.len + 1); 604 break; 605 default: 606 rc = EINVAL; 607 } 608 609 out: 610 xbs->len = 0; 611 return (rc); 612 } 613 614 /*ARGSUSED*/ 615 static int 616 xenbusdrv_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 617 size_t *maplen, uint_t model) 618 { 619 xenbus_dev_t *xbs; 620 int err; 621 622 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 623 624 if (off != 0 || len != PAGESIZE) 625 return (-1); 626 627 if (!DOMAIN_IS_INITDOMAIN(xen_info)) 628 return (-1); 629 630 err = devmap_umem_setup(dhp, xbs->dip, NULL, xb_xenstore_cookie(), 631 0, PAGESIZE, PROT_READ | PROT_WRITE | PROT_USER, 0, NULL); 632 633 if (err) 634 return (err); 635 636 *maplen = PAGESIZE; 637 638 return (0); 639 } 640 641 static int 642 xenbusdrv_segmap(dev_t dev, off_t off, ddi_as_handle_t as, caddr_t *addrp, 643 off_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr) 644 { 645 646 if (secpolicy_xvm_control(cr)) 647 return (EPERM); 648 649 return (ddi_devmap_segmap(dev, off, as, addrp, len, prot, 650 maxprot, flags, cr)); 651 } 652 653 /*ARGSUSED*/ 654 static int 655 xenbusdrv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, 656 int *rvalp) 657 { 658 xenbus_dev_t *xbs; 659 660 if (secpolicy_xvm_control(cr)) 661 return (EPERM); 662 663 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 664 switch (cmd) { 665 case IOCTL_XENBUS_XENSTORE_EVTCHN: 666 *rvalp = xen_info->store_evtchn; 667 break; 668 case IOCTL_XENBUS_NOTIFY_UP: 669 xs_notify_xenstore_up(); 670 xbs->xenstore_inst = 1; 671 break; 672 default: 673 return (EINVAL); 674 } 675 676 return (0); 677 } 678