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, NULL } 193 }; 194 195 int 196 _init(void) 197 { 198 int e; 199 200 e = ddi_soft_state_init(&xenbusdrv_statep, sizeof (xenbus_dev_t), 1); 201 if (e) 202 return (e); 203 204 e = mod_install(&modlinkage); 205 if (e) 206 ddi_soft_state_fini(&xenbusdrv_statep); 207 208 return (e); 209 } 210 211 int 212 _fini(void) 213 { 214 int e; 215 216 e = mod_remove(&modlinkage); 217 if (e) 218 return (e); 219 220 ddi_soft_state_fini(&xenbusdrv_statep); 221 222 return (0); 223 } 224 225 int 226 _info(struct modinfo *modinfop) 227 { 228 return (mod_info(&modlinkage, modinfop)); 229 } 230 231 /* ARGSUSED */ 232 static int 233 xenbusdrv_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 234 { 235 dev_t dev = (dev_t)arg; 236 minor_t minor = getminor(dev); 237 int retval; 238 239 switch (cmd) { 240 case DDI_INFO_DEVT2DEVINFO: 241 if (minor != 0 || xenbusdrv_dip == NULL) { 242 *result = (void *)NULL; 243 retval = DDI_FAILURE; 244 } else { 245 *result = (void *)xenbusdrv_dip; 246 retval = DDI_SUCCESS; 247 } 248 break; 249 case DDI_INFO_DEVT2INSTANCE: 250 *result = (void *)0; 251 retval = DDI_SUCCESS; 252 break; 253 default: 254 retval = DDI_FAILURE; 255 } 256 return (retval); 257 } 258 259 static int 260 xenbusdrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 261 { 262 int error; 263 int unit = ddi_get_instance(dip); 264 265 266 switch (cmd) { 267 case DDI_ATTACH: 268 break; 269 case DDI_RESUME: 270 return (DDI_SUCCESS); 271 default: 272 cmn_err(CE_WARN, "xenbus_attach: unknown cmd 0x%x\n", cmd); 273 return (DDI_FAILURE); 274 } 275 276 /* DDI_ATTACH */ 277 278 /* 279 * only one instance - but we clone using the open routine 280 */ 281 if (ddi_get_instance(dip) > 0) 282 return (DDI_FAILURE); 283 284 mutex_init(&xenbusdrv_clone_tab_mutex, NULL, MUTEX_DRIVER, 285 NULL); 286 287 error = ddi_create_minor_node(dip, "xenbus", S_IFCHR, unit, 288 DDI_PSEUDO, NULL); 289 if (error != DDI_SUCCESS) 290 goto fail; 291 292 /* 293 * save dip for getinfo 294 */ 295 xenbusdrv_dip = dip; 296 ddi_report_dev(dip); 297 298 #ifndef XPV_HVM_DRIVER 299 if (DOMAIN_IS_INITDOMAIN(xen_info)) 300 xs_dom0_init(); 301 #endif 302 303 return (DDI_SUCCESS); 304 305 fail: 306 (void) xenbusdrv_detach(dip, DDI_DETACH); 307 return (error); 308 } 309 310 static int 311 xenbusdrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 312 { 313 /* 314 * again, only one instance 315 */ 316 if (ddi_get_instance(dip) > 0) 317 return (DDI_FAILURE); 318 319 switch (cmd) { 320 case DDI_DETACH: 321 ddi_remove_minor_node(dip, NULL); 322 mutex_destroy(&xenbusdrv_clone_tab_mutex); 323 xenbusdrv_dip = NULL; 324 return (DDI_SUCCESS); 325 case DDI_SUSPEND: 326 return (DDI_SUCCESS); 327 default: 328 cmn_err(CE_WARN, "xenbus_detach: unknown cmd 0x%x\n", cmd); 329 return (DDI_FAILURE); 330 } 331 } 332 333 /* ARGSUSED */ 334 static int 335 xenbusdrv_open(dev_t *devp, int flag, int otyp, cred_t *cr) 336 { 337 xenbus_dev_t *xbs; 338 minor_t minor = getminor(*devp); 339 340 if (otyp == OTYP_BLK) 341 return (ENXIO); 342 343 /* 344 * only allow open on minor = 0 - the clone device 345 */ 346 if (minor != 0) 347 return (ENXIO); 348 349 /* 350 * find a free slot and grab it 351 */ 352 mutex_enter(&xenbusdrv_clone_tab_mutex); 353 for (minor = 1; minor < XENBUSDRV_NCLONES; minor++) { 354 if (xenbusdrv_clone_tab[minor] == 0) { 355 xenbusdrv_clone_tab[minor] = 1; 356 break; 357 } 358 } 359 mutex_exit(&xenbusdrv_clone_tab_mutex); 360 if (minor == XENBUSDRV_NCLONES) 361 return (EAGAIN); 362 363 /* Allocate softstate structure */ 364 if (ddi_soft_state_zalloc(xenbusdrv_statep, 365 XENBUSDRV_MINOR2INST(minor)) != DDI_SUCCESS) { 366 mutex_enter(&xenbusdrv_clone_tab_mutex); 367 xenbusdrv_clone_tab[minor] = 0; 368 mutex_exit(&xenbusdrv_clone_tab_mutex); 369 return (EAGAIN); 370 } 371 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor)); 372 373 /* ... and init it */ 374 xbs->dip = xenbusdrv_dip; 375 mutex_init(&xbs->read_mutex, NULL, MUTEX_DRIVER, NULL); 376 cv_init(&xbs->read_cv, NULL, CV_DEFAULT, NULL); 377 list_create(&xbs->transactions, sizeof (struct xenbus_dev_transaction), 378 offsetof(struct xenbus_dev_transaction, list)); 379 380 /* clone driver */ 381 *devp = makedevice(getmajor(*devp), minor); 382 XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv open succeeded, minor=%d", 383 minor)); 384 385 return (0); 386 } 387 388 /* ARGSUSED */ 389 static int 390 xenbusdrv_close(dev_t dev, int flag, int otyp, struct cred *cr) 391 { 392 xenbus_dev_t *xbs; 393 minor_t minor = getminor(dev); 394 struct xenbus_dev_transaction *trans; 395 396 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor)); 397 if (xbs == NULL) 398 return (ENXIO); 399 400 #ifdef notyet 401 /* 402 * XXPV - would like to be able to notify xenstore down here, but 403 * as the daemon is currently written, it doesn't leave the device 404 * open after initial setup, so we have no way of knowing if it has 405 * gone away. 406 */ 407 if (xbs->xenstore_inst) 408 xs_notify_xenstore_down(); 409 #endif 410 /* free pending transaction */ 411 while (trans = (struct xenbus_dev_transaction *) 412 list_head(&xbs->transactions)) { 413 (void) xenbus_transaction_end(trans->handle, 1); 414 list_remove(&xbs->transactions, (void *)trans); 415 kmem_free(trans, sizeof (*trans)); 416 } 417 418 mutex_destroy(&xbs->read_mutex); 419 cv_destroy(&xbs->read_cv); 420 ddi_soft_state_free(xenbusdrv_statep, XENBUSDRV_MINOR2INST(minor)); 421 422 /* 423 * free clone tab slot 424 */ 425 mutex_enter(&xenbusdrv_clone_tab_mutex); 426 xenbusdrv_clone_tab[minor] = 0; 427 mutex_exit(&xenbusdrv_clone_tab_mutex); 428 429 XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv close succeeded, minor=%d", 430 minor)); 431 432 return (0); 433 } 434 435 /* ARGSUSED */ 436 static int 437 xenbusdrv_read(dev_t dev, struct uio *uiop, cred_t *cr) 438 { 439 xenbus_dev_t *xbs; 440 size_t len; 441 int res, ret; 442 int idx; 443 444 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_read called")); 445 446 if (secpolicy_xvm_control(cr)) 447 return (EPERM); 448 449 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 450 451 mutex_enter(&xbs->read_mutex); 452 453 /* check if we have something to read */ 454 while (xbs->read_prod == xbs->read_cons) { 455 if (cv_wait_sig(&xbs->read_cv, &xbs->read_mutex) == 0) { 456 mutex_exit(&xbs->read_mutex); 457 return (EINTR); 458 } 459 } 460 461 idx = XENBUSDRV_MASK_READ_IDX(xbs->read_cons); 462 res = uiop->uio_resid; 463 464 len = xbs->read_prod - xbs->read_cons; 465 466 if (len > (sizeof (xbs->read_buffer) - idx)) 467 len = sizeof (xbs->read_buffer) - idx; 468 if (len > res) 469 len = res; 470 471 ret = uiomove(xbs->read_buffer + idx, len, UIO_READ, uiop); 472 xbs->read_cons += res - uiop->uio_resid; 473 mutex_exit(&xbs->read_mutex); 474 475 return (ret); 476 } 477 478 /* 479 * prepare data for xenbusdrv_read() 480 */ 481 static int 482 xenbusdrv_queue_reply(xenbus_dev_t *xbs, const struct xsd_sockmsg *msg, 483 const char *reply) 484 { 485 int i; 486 int remaining; 487 488 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply called")); 489 490 mutex_enter(&xbs->read_mutex); 491 492 remaining = sizeof (xbs->read_buffer) - 493 (xbs->read_prod - xbs->read_cons); 494 495 if (sizeof (*msg) + msg->len > remaining) { 496 mutex_exit(&xbs->read_mutex); 497 return (EOVERFLOW); 498 } 499 500 for (i = 0; i < sizeof (*msg); i++, xbs->read_prod++) { 501 xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] = 502 ((char *)msg)[i]; 503 } 504 505 for (i = 0; i < msg->len; i++, xbs->read_prod++) { 506 xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] = 507 reply[i]; 508 } 509 510 cv_broadcast(&xbs->read_cv); 511 512 mutex_exit(&xbs->read_mutex); 513 514 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply exited")); 515 516 return (0); 517 } 518 519 /* ARGSUSED */ 520 static int 521 xenbusdrv_write(dev_t dev, struct uio *uiop, cred_t *cr) 522 { 523 xenbus_dev_t *xbs; 524 struct xenbus_dev_transaction *trans; 525 void *reply; 526 size_t len; 527 int rc = 0; 528 529 XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_write called")); 530 531 if (secpolicy_xvm_control(cr)) 532 return (EPERM); 533 534 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 535 len = uiop->uio_resid; 536 537 if ((len + xbs->len) > sizeof (xbs->u.buffer)) { 538 XENBUSDRV_DBPRINT((CE_WARN, "Request is too big")); 539 rc = EINVAL; 540 goto out; 541 } 542 543 if (uiomove(xbs->u.buffer + xbs->len, len, UIO_WRITE, uiop) != 0) { 544 XENBUSDRV_DBPRINT((CE_WARN, "Uiomove failed")); 545 rc = EFAULT; 546 goto out; 547 } 548 549 xbs->len += len; 550 551 if (xbs->len < (sizeof (xbs->u.msg)) || 552 xbs->len < (sizeof (xbs->u.msg) + xbs->u.msg.len)) { 553 XENBUSDRV_DBPRINT((CE_NOTE, "Partial request")); 554 return (0); 555 } 556 557 switch (xbs->u.msg.type) { 558 case XS_TRANSACTION_START: 559 case XS_TRANSACTION_END: 560 case XS_DIRECTORY: 561 case XS_READ: 562 case XS_GET_PERMS: 563 case XS_RELEASE: 564 case XS_GET_DOMAIN_PATH: 565 case XS_WRITE: 566 case XS_MKDIR: 567 case XS_RM: 568 case XS_SET_PERMS: 569 /* send the request to xenstore and get feedback */ 570 rc = xenbus_dev_request_and_reply(&xbs->u.msg, &reply); 571 if (rc) { 572 XENBUSDRV_DBPRINT((CE_WARN, 573 "xenbus_dev_request_and_reply failed")); 574 goto out; 575 } 576 577 /* handle transaction start/end */ 578 if (xbs->u.msg.type == XS_TRANSACTION_START) { 579 trans = kmem_alloc(sizeof (*trans), KM_SLEEP); 580 (void) ddi_strtoul((char *)reply, NULL, 0, 581 (unsigned long *)&trans->handle); 582 list_insert_tail(&xbs->transactions, (void *)trans); 583 } else if (xbs->u.msg.type == XS_TRANSACTION_END) { 584 /* try to find out the ending transaction */ 585 for (trans = (struct xenbus_dev_transaction *) 586 list_head(&xbs->transactions); trans; 587 trans = (struct xenbus_dev_transaction *) 588 list_next(&xbs->transactions, (void *)trans)) 589 if (trans->handle == 590 (xenbus_transaction_t) 591 xbs->u.msg.tx_id) 592 break; 593 ASSERT(trans); 594 /* free it, if we find it */ 595 list_remove(&xbs->transactions, (void *)trans); 596 kmem_free(trans, sizeof (*trans)); 597 } 598 599 /* prepare data for xenbusdrv_read() to get */ 600 rc = xenbusdrv_queue_reply(xbs, &xbs->u.msg, reply); 601 602 kmem_free(reply, xbs->u.msg.len + 1); 603 break; 604 default: 605 rc = EINVAL; 606 } 607 608 out: 609 xbs->len = 0; 610 return (rc); 611 } 612 613 /*ARGSUSED*/ 614 static int 615 xenbusdrv_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 616 size_t *maplen, uint_t model) 617 { 618 xenbus_dev_t *xbs; 619 int err; 620 621 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 622 623 if (off != 0 || len != PAGESIZE) 624 return (-1); 625 626 if (!DOMAIN_IS_INITDOMAIN(xen_info)) 627 return (-1); 628 629 err = devmap_umem_setup(dhp, xbs->dip, NULL, xb_xenstore_cookie(), 630 0, PAGESIZE, PROT_READ | PROT_WRITE | PROT_USER, 0, NULL); 631 632 if (err) 633 return (err); 634 635 *maplen = PAGESIZE; 636 637 return (0); 638 } 639 640 static int 641 xenbusdrv_segmap(dev_t dev, off_t off, ddi_as_handle_t as, caddr_t *addrp, 642 off_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr) 643 { 644 645 if (secpolicy_xvm_control(cr)) 646 return (EPERM); 647 648 return (ddi_devmap_segmap(dev, off, as, addrp, len, prot, 649 maxprot, flags, cr)); 650 } 651 652 /*ARGSUSED*/ 653 static int 654 xenbusdrv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, 655 int *rvalp) 656 { 657 xenbus_dev_t *xbs; 658 659 if (secpolicy_xvm_control(cr)) 660 return (EPERM); 661 662 xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev))); 663 switch (cmd) { 664 case IOCTL_XENBUS_XENSTORE_EVTCHN: 665 *rvalp = xen_info->store_evtchn; 666 break; 667 case IOCTL_XENBUS_NOTIFY_UP: 668 xs_notify_xenstore_up(); 669 xbs->xenstore_inst = 1; 670 break; 671 default: 672 return (EINVAL); 673 } 674 675 return (0); 676 }