1 /* $NetBSD: rump.c,v 1.221 2011/01/22 18:33:25 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by Google Summer of Code. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.221 2011/01/22 18:33:25 pooka Exp $"); 32 33 #include <sys/systm.h> 34 #define ELFSIZE ARCH_ELFSIZE 35 36 #include <sys/param.h> 37 #include <sys/atomic.h> 38 #include <sys/buf.h> 39 #include <sys/callout.h> 40 #include <sys/conf.h> 41 #include <sys/cpu.h> 42 #include <sys/device.h> 43 #include <sys/evcnt.h> 44 #include <sys/event.h> 45 #include <sys/exec_elf.h> 46 #include <sys/filedesc.h> 47 #include <sys/iostat.h> 48 #include <sys/kauth.h> 49 #include <sys/kernel.h> 50 #include <sys/kmem.h> 51 #include <sys/kprintf.h> 52 #include <sys/kthread.h> 53 #include <sys/ksyms.h> 54 #include <sys/msgbuf.h> 55 #include <sys/module.h> 56 #include <sys/once.h> 57 #include <sys/percpu.h> 58 #include <sys/pipe.h> 59 #include <sys/pool.h> 60 #include <sys/queue.h> 61 #include <sys/reboot.h> 62 #include <sys/resourcevar.h> 63 #include <sys/select.h> 64 #include <sys/sysctl.h> 65 #include <sys/syscall.h> 66 #include <sys/syscallvar.h> 67 #include <sys/timetc.h> 68 #include <sys/tty.h> 69 #include <sys/uidinfo.h> 70 #include <sys/vmem.h> 71 #include <sys/xcall.h> 72 #include <sys/simplelock.h> 73 74 #include <rump/rumpuser.h> 75 76 #include <secmodel/suser/suser.h> 77 78 #include <prop/proplib.h> 79 80 #include <uvm/uvm_extern.h> 81 #include <uvm/uvm_readahead.h> 82 83 #include "rump_private.h" 84 #include "rump_net_private.h" 85 #include "rump_vfs_private.h" 86 #include "rump_dev_private.h" 87 88 char machine[] = MACHINE; 89 90 struct proc *initproc; 91 92 struct device rump_rootdev = { 93 .dv_class = DV_VIRTUAL 94 }; 95 96 #ifdef RUMP_WITHOUT_THREADS 97 int rump_threads = 0; 98 #else 99 int rump_threads = 1; 100 #endif 101 102 static int rump_proxy_syscall(int, void *, register_t *); 103 static int rump_proxy_rfork(void *, int); 104 static void rump_proxy_procexit(void); 105 106 static char rump_msgbuf[16*1024]; /* 16k should be enough for std rump needs */ 107 108 #ifdef LOCKDEBUG 109 const int rump_lockdebug = 1; 110 #else 111 const int rump_lockdebug = 0; 112 #endif 113 bool rump_ttycomponent = false; 114 115 static void 116 rump_aiodone_worker(struct work *wk, void *dummy) 117 { 118 struct buf *bp = (struct buf *)wk; 119 120 KASSERT(&bp->b_work == wk); 121 bp->b_iodone(bp); 122 } 123 124 static int rump_inited; 125 126 /* 127 * Make sure pnbuf_cache is available even without vfs 128 */ 129 struct pool_cache *pnbuf_cache; 130 int rump_initpnbufpool(void); 131 int rump_initpnbufpool(void) 132 { 133 134 pnbuf_cache = pool_cache_init(MAXPATHLEN, 0, 0, 0, "pnbufpl", 135 NULL, IPL_NONE, NULL, NULL, NULL); 136 return EOPNOTSUPP; 137 } 138 139 int rump__unavailable(void); 140 int rump__unavailable() {return EOPNOTSUPP;} 141 __weak_alias(rump_net_init,rump__unavailable); 142 __weak_alias(rump_vfs_init,rump_initpnbufpool); 143 __weak_alias(rump_dev_init,rump__unavailable); 144 145 __weak_alias(rump_vfs_fini,rump__unavailable); 146 147 __weak_alias(biodone,rump__unavailable); 148 __weak_alias(sopoll,rump__unavailable); 149 150 __weak_alias(rump_vfs_drainbufs,rump__unavailable); 151 152 void rump__unavailable_vfs_panic(void); 153 void rump__unavailable_vfs_panic() {panic("vfs component not available");} 154 __weak_alias(usermount_common_policy,rump__unavailable_vfs_panic); 155 156 /* easier to write vfs-less clients */ 157 __weak_alias(rump_pub_etfs_register,rump__unavailable); 158 __weak_alias(rump_pub_etfs_remove,rump__unavailable); 159 160 rump_proc_vfs_init_fn rump_proc_vfs_init; 161 rump_proc_vfs_release_fn rump_proc_vfs_release; 162 163 static void add_linkedin_modules(const struct modinfo *const *, size_t); 164 165 static void __noinline 166 messthestack(void) 167 { 168 volatile uint32_t mess[64]; 169 uint64_t d1, d2; 170 int i, error; 171 172 for (i = 0; i < 64; i++) { 173 rumpuser_gettime(&d1, &d2, &error); 174 mess[i] = d2; 175 } 176 } 177 178 /* 179 * Create kern.hostname. why only this you ask. well, init_sysctl 180 * is a kitchen sink in need of some gardening. but i want to use 181 * kern.hostname today. 182 */ 183 static void 184 mksysctls(void) 185 { 186 187 sysctl_createv(NULL, 0, NULL, NULL, 188 CTLFLAG_PERMANENT, CTLTYPE_NODE, "kern", NULL, 189 NULL, 0, NULL, 0, CTL_KERN, CTL_EOL); 190 191 /* XXX: setting hostnamelen is missing */ 192 sysctl_createv(NULL, 0, NULL, NULL, 193 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_STRING, "hostname", 194 SYSCTL_DESCR("System hostname"), NULL, 0, 195 &hostname, MAXHOSTNAMELEN, CTL_KERN, KERN_HOSTNAME, CTL_EOL); 196 } 197 198 /* there's no convenient kernel entry point for this, so just craft out own */ 199 static pid_t 200 spgetpid(void) 201 { 202 203 return curproc->p_pid; 204 } 205 206 static const struct rumpuser_sp_ops spops = { 207 .spop_schedule = rump_schedule, 208 .spop_unschedule = rump_unschedule, 209 .spop_lwproc_switch = rump_lwproc_switch, 210 .spop_lwproc_release = rump_lwproc_releaselwp, 211 .spop_lwproc_rfork = rump_proxy_rfork, 212 .spop_lwproc_newlwp = rump_lwproc_newlwp, 213 .spop_lwproc_curlwp = rump_lwproc_curlwp, 214 .spop_procexit = rump_proxy_procexit, 215 .spop_syscall = rump_proxy_syscall, 216 .spop_getpid = spgetpid, 217 }; 218 219 int 220 rump_daemonize_begin(void) 221 { 222 223 if (rump_inited) 224 return EALREADY; 225 226 return rumpuser_daemonize_begin(); 227 } 228 229 int 230 rump_daemonize_done(int error) 231 { 232 233 return rumpuser_daemonize_done(error); 234 } 235 236 int 237 rump__init(int rump_version) 238 { 239 char buf[256]; 240 struct timespec ts; 241 uint64_t sec, nsec; 242 struct lwp *l; 243 int i, numcpu; 244 int error; 245 246 /* not reentrant */ 247 if (rump_inited) 248 return 0; 249 else if (rump_inited == -1) 250 panic("rump_init: host process restart required"); 251 else 252 rump_inited = 1; 253 254 if (rumpuser_getversion() != RUMPUSER_VERSION) { 255 /* let's hope the ABI of rumpuser_dprintf is the same ;) */ 256 rumpuser_dprintf("rumpuser version mismatch: %d vs. %d\n", 257 rumpuser_getversion(), RUMPUSER_VERSION); 258 return EPROGMISMATCH; 259 } 260 261 if (rumpuser_getenv("RUMP_VERBOSE", buf, sizeof(buf), &error) == 0) { 262 if (*buf != '0') 263 boothowto = AB_VERBOSE; 264 } 265 266 if (rumpuser_getenv("RUMP_NCPU", buf, sizeof(buf), &error) == 0) 267 error = 0; 268 if (error == 0) { 269 numcpu = strtoll(buf, NULL, 10); 270 if (numcpu < 1) 271 numcpu = 1; 272 } else { 273 numcpu = rumpuser_getnhostcpu(); 274 } 275 rump_cpus_bootstrap(&numcpu); 276 277 rumpuser_gettime(&sec, &nsec, &error); 278 boottime.tv_sec = sec; 279 boottime.tv_nsec = nsec; 280 281 initmsgbuf(rump_msgbuf, sizeof(rump_msgbuf)); 282 aprint_verbose("%s%s", copyright, version); 283 284 /* 285 * Seed arc4random() with a "reasonable" amount of randomness. 286 * Yes, this is a quick kludge which depends on the arc4random 287 * implementation. 288 */ 289 messthestack(); 290 arc4random(); 291 292 if (rump_version != RUMP_VERSION) { 293 printf("rump version mismatch, %d vs. %d\n", 294 rump_version, RUMP_VERSION); 295 return EPROGMISMATCH; 296 } 297 298 if (rumpuser_getenv("RUMP_THREADS", buf, sizeof(buf), &error) == 0) { 299 rump_threads = *buf != '0'; 300 } 301 rumpuser_thrinit(rump_user_schedule, rump_user_unschedule, 302 rump_threads); 303 rump_intr_init(numcpu); 304 rump_tsleep_init(); 305 306 /* init minimal lwp/cpu context */ 307 l = &lwp0; 308 l->l_lid = 1; 309 l->l_cpu = l->l_target_cpu = rump_cpu; 310 l->l_fd = &filedesc0; 311 rumpuser_set_curlwp(l); 312 313 rumpuser_mutex_init(&rump_giantlock); 314 ksyms_init(); 315 uvm_init(); 316 evcnt_init(); 317 318 once_init(); 319 kernconfig_lock_init(); 320 prop_kern_init(); 321 322 pool_subsystem_init(); 323 kmem_init(); 324 325 uvm_ra_init(); 326 uao_init(); 327 328 mutex_obj_init(); 329 callout_startup(); 330 331 kprintf_init(); 332 loginit(); 333 334 kauth_init(); 335 336 procinit(); 337 proc0_init(); 338 uid_init(); 339 chgproccnt(0, 1); 340 341 l->l_proc = &proc0; 342 lwp_update_creds(l); 343 344 lwpinit_specificdata(); 345 lwp_initspecific(&lwp0); 346 347 rump_scheduler_init(numcpu); 348 /* revert temporary context and schedule a semireal context */ 349 l->l_cpu = NULL; 350 rumpuser_set_curlwp(NULL); 351 initproc = &proc0; /* borrow proc0 before we get initproc started */ 352 rump_schedule(); 353 354 percpu_init(); 355 inittimecounter(); 356 ntp_init(); 357 358 rumpuser_gettime(&sec, &nsec, &error); 359 ts.tv_sec = sec; 360 ts.tv_nsec = nsec; 361 tc_setclock(&ts); 362 363 /* we are mostly go. do per-cpu subsystem init */ 364 for (i = 0; i < numcpu; i++) { 365 struct cpu_info *ci = cpu_lookup(i); 366 367 /* attach non-bootstrap CPUs */ 368 if (i > 0) { 369 rump_cpu_attach(ci); 370 ncpu++; 371 } 372 373 callout_init_cpu(ci); 374 softint_init(ci); 375 xc_init_cpu(ci); 376 pool_cache_cpu_init(ci); 377 selsysinit(ci); 378 percpu_init_cpu(ci); 379 380 TAILQ_INIT(&ci->ci_data.cpu_ld_locks); 381 __cpu_simple_lock_init(&ci->ci_data.cpu_ld_lock); 382 383 aprint_verbose("cpu%d at thinair0: rump virtual cpu\n", i); 384 } 385 386 sysctl_init(); 387 mksysctls(); 388 kqueue_init(); 389 iostat_init(); 390 fd_sys_init(); 391 module_init(); 392 devsw_init(); 393 pipe_init(); 394 resource_init(); 395 396 /* start page baroness */ 397 if (rump_threads) { 398 if (kthread_create(PRI_PGDAEMON, KTHREAD_MPSAFE, NULL, 399 uvm_pageout, NULL, &uvm.pagedaemon_lwp, "pdaemon") != 0) 400 panic("pagedaemon create failed"); 401 } else 402 uvm.pagedaemon_lwp = NULL; /* doesn't match curlwp */ 403 404 /* process dso's */ 405 rumpuser_dl_bootstrap(add_linkedin_modules, rump_kernelfsym_load); 406 407 rump_component_init(RUMP_COMPONENT_KERN); 408 409 /* these do nothing if not present */ 410 rump_vfs_init(); 411 rump_net_init(); 412 rump_dev_init(); 413 414 rump_component_init(RUMP_COMPONENT_KERN_VFS); 415 416 /* 417 * if we initialized the tty component above, the tyttymtx is 418 * now initialized. otherwise, we need to initialize it. 419 */ 420 if (!rump_ttycomponent) 421 mutex_init(&tty_lock, MUTEX_DEFAULT, IPL_VM); 422 423 cold = 0; 424 425 /* aieeeedondest */ 426 if (rump_threads) { 427 if (workqueue_create(&uvm.aiodone_queue, "aiodoned", 428 rump_aiodone_worker, NULL, 0, 0, WQ_MPSAFE)) 429 panic("aiodoned"); 430 } 431 432 sysctl_finalize(); 433 434 module_init_class(MODULE_CLASS_ANY); 435 436 rumpuser_gethostname(hostname, MAXHOSTNAMELEN, &error); 437 hostnamelen = strlen(hostname); 438 439 sigemptyset(&sigcantmask); 440 441 if (rump_threads) 442 vmem_rehash_start(); 443 444 /* 445 * Create init, used to attach implicit threads in rump. 446 * (note: must be done after vfsinit to get cwdi) 447 */ 448 (void)rump__lwproc_alloclwp(NULL); /* dummy thread for initproc */ 449 mutex_enter(proc_lock); 450 initproc = proc_find_raw(1); 451 mutex_exit(proc_lock); 452 if (initproc == NULL) 453 panic("where in the world is initproc?"); 454 455 /* 456 * Adjust syscall vector in case factions were dlopen()'d 457 * before calling rump_init(). 458 * (modules will handle dynamic syscalls the usual way) 459 * 460 * Note: this will adjust the function vectors of 461 * syscalls which use a funcalias (getpid etc.), but 462 * it makes no difference. 463 */ 464 for (i = 0; i < SYS_NSYSENT; i++) { 465 void *sym; 466 467 if (rump_sysent[i].sy_flags & SYCALL_NOSYS || 468 *syscallnames[i] == '#' || 469 rump_sysent[i].sy_call == sys_nomodule) 470 continue; 471 472 /* if present, adjust symbol value */ 473 sprintf(buf, "rumpns_sys_%s", syscallnames[i]); 474 if ((sym = rumpuser_dl_globalsym(buf)) != NULL 475 && sym != rump_sysent[i].sy_call) { 476 #if 0 477 rumpuser_dprintf("adjusting %s: %p (old %p)\n", 478 syscallnames[i], sym, rump_sysent[i].sy_call); 479 #endif 480 rump_sysent[i].sy_call = sym; 481 } 482 } 483 484 /* release cpu */ 485 rump_unschedule(); 486 487 return 0; 488 } 489 490 int 491 rump_init_server(const char *url) 492 { 493 494 return rumpuser_sp_init(url, &spops, ostype, osrelease, MACHINE); 495 } 496 497 void 498 cpu_reboot(int howto, char *bootstr) 499 { 500 int ruhow = 0; 501 void *finiarg; 502 503 printf("rump kernel halting...\n"); 504 505 if (!RUMP_LOCALPROC_P(curproc)) 506 finiarg = curproc->p_vmspace->vm_map.pmap; 507 else 508 finiarg = NULL; 509 rumpuser_sp_fini(finiarg); 510 511 /* dump means we really take the dive here */ 512 if ((howto & RB_DUMP) || panicstr) { 513 ruhow = RUMPUSER_PANIC; 514 goto out; 515 } 516 517 /* try to sync */ 518 if (!((howto & RB_NOSYNC) || panicstr)) { 519 rump_vfs_fini(); 520 } 521 522 /* your wish is my command */ 523 if (howto & RB_HALT) { 524 printf("rump kernel halted\n"); 525 for (;;) { 526 uint64_t sec = 5, nsec = 0; 527 int error; 528 529 rumpuser_nanosleep(&sec, &nsec, &error); 530 } 531 } 532 533 /* this function is __dead, we must exit */ 534 out: 535 printf("halted\n"); 536 rumpuser_exit(ruhow); 537 } 538 539 struct uio * 540 rump_uio_setup(void *buf, size_t bufsize, off_t offset, enum rump_uiorw rw) 541 { 542 struct uio *uio; 543 enum uio_rw uiorw; 544 545 switch (rw) { 546 case RUMPUIO_READ: 547 uiorw = UIO_READ; 548 break; 549 case RUMPUIO_WRITE: 550 uiorw = UIO_WRITE; 551 break; 552 default: 553 panic("%s: invalid rw %d", __func__, rw); 554 } 555 556 uio = kmem_alloc(sizeof(struct uio), KM_SLEEP); 557 uio->uio_iov = kmem_alloc(sizeof(struct iovec), KM_SLEEP); 558 559 uio->uio_iov->iov_base = buf; 560 uio->uio_iov->iov_len = bufsize; 561 562 uio->uio_iovcnt = 1; 563 uio->uio_offset = offset; 564 uio->uio_resid = bufsize; 565 uio->uio_rw = uiorw; 566 UIO_SETUP_SYSSPACE(uio); 567 568 return uio; 569 } 570 571 size_t 572 rump_uio_getresid(struct uio *uio) 573 { 574 575 return uio->uio_resid; 576 } 577 578 off_t 579 rump_uio_getoff(struct uio *uio) 580 { 581 582 return uio->uio_offset; 583 } 584 585 size_t 586 rump_uio_free(struct uio *uio) 587 { 588 size_t resid; 589 590 resid = uio->uio_resid; 591 kmem_free(uio->uio_iov, sizeof(*uio->uio_iov)); 592 kmem_free(uio, sizeof(*uio)); 593 594 return resid; 595 } 596 597 kauth_cred_t 598 rump_cred_create(uid_t uid, gid_t gid, size_t ngroups, gid_t *groups) 599 { 600 kauth_cred_t cred; 601 int rv; 602 603 cred = kauth_cred_alloc(); 604 kauth_cred_setuid(cred, uid); 605 kauth_cred_seteuid(cred, uid); 606 kauth_cred_setsvuid(cred, uid); 607 kauth_cred_setgid(cred, gid); 608 kauth_cred_setgid(cred, gid); 609 kauth_cred_setegid(cred, gid); 610 kauth_cred_setsvgid(cred, gid); 611 rv = kauth_cred_setgroups(cred, groups, ngroups, 0, UIO_SYSSPACE); 612 /* oh this is silly. and by "this" I mean kauth_cred_setgroups() */ 613 assert(rv == 0); 614 615 return cred; 616 } 617 618 void 619 rump_cred_put(kauth_cred_t cred) 620 { 621 622 kauth_cred_free(cred); 623 } 624 625 static int compcounter[RUMP_COMPONENT_MAX]; 626 627 static void 628 rump_component_init_cb(struct rump_component *rc, int type) 629 { 630 631 KASSERT(type < RUMP_COMPONENT_MAX); 632 if (rc->rc_type == type) { 633 rc->rc_init(); 634 compcounter[type]++; 635 } 636 } 637 638 int 639 rump_component_count(enum rump_component_type type) 640 { 641 642 KASSERT(type <= RUMP_COMPONENT_MAX); 643 return compcounter[type]; 644 } 645 646 void 647 rump_component_init(enum rump_component_type type) 648 { 649 650 rumpuser_dl_component_init(type, rump_component_init_cb); 651 } 652 653 /* 654 * Initialize a module which has already been loaded and linked 655 * with dlopen(). This is fundamentally the same as a builtin module. 656 */ 657 int 658 rump_module_init(const struct modinfo * const *mip, size_t nmodinfo) 659 { 660 661 return module_builtin_add(mip, nmodinfo, true); 662 } 663 664 /* 665 * Finish module (flawless victory, fatality!). 666 */ 667 int 668 rump_module_fini(const struct modinfo *mi) 669 { 670 671 return module_builtin_remove(mi, true); 672 } 673 674 /* 675 * Add loaded and linked module to the builtin list. It will 676 * later be initialized with module_init_class(). 677 */ 678 679 static void 680 add_linkedin_modules(const struct modinfo * const *mip, size_t nmodinfo) 681 { 682 683 module_builtin_add(mip, nmodinfo, false); 684 } 685 686 int 687 rump_kernelfsym_load(void *symtab, uint64_t symsize, 688 char *strtab, uint64_t strsize) 689 { 690 static int inited = 0; 691 Elf64_Ehdr ehdr; 692 693 if (inited) 694 return EBUSY; 695 inited = 1; 696 697 /* 698 * Use 64bit header since it's bigger. Shouldn't make a 699 * difference, since we're passing in all zeroes anyway. 700 */ 701 memset(&ehdr, 0, sizeof(ehdr)); 702 ksyms_addsyms_explicit(&ehdr, symtab, symsize, strtab, strsize); 703 704 return 0; 705 } 706 707 static int 708 rump_proxy_syscall(int num, void *arg, register_t *retval) 709 { 710 struct lwp *l; 711 struct sysent *callp; 712 int rv; 713 714 if (__predict_false(num >= SYS_NSYSENT)) 715 return ENOSYS; 716 717 callp = rump_sysent + num; 718 l = curlwp; 719 rv = sy_call(callp, l, (void *)arg, retval); 720 721 return rv; 722 } 723 724 static int 725 rump_proxy_rfork(void *priv, int flags) 726 { 727 struct vmspace *newspace; 728 int error; 729 730 if ((error = rump_lwproc_rfork(flags)) != 0) 731 return error; 732 733 /* 734 * Since it's a proxy proc, adjust the vmspace. 735 * Refcount will eternally be 1. 736 */ 737 newspace = kmem_alloc(sizeof(*newspace), KM_SLEEP); 738 newspace->vm_refcnt = 1; 739 newspace->vm_map.pmap = priv; 740 KASSERT(curproc->p_vmspace == vmspace_kernel()); 741 curproc->p_vmspace = newspace; 742 743 return 0; 744 } 745 746 static void 747 rump_proxy_procexit(void) 748 { 749 struct proc *p = curproc; 750 uint64_t where; 751 struct lwp *l; 752 753 mutex_enter(p->p_lock); 754 /* 755 * First pass: mark all lwps in the process with LSDEAD 756 * so that they know they should exit. 757 */ 758 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 759 if (l == curlwp) 760 continue; 761 l->l_stat = LSDEAD; 762 } 763 mutex_exit(p->p_lock); 764 765 /* 766 * Next, make sure everyone on all CPUs sees our status 767 * update. This keeps threads inside cv_wait() and makes 768 * sure we don't access a stale cv pointer later when 769 * we wake up the threads. 770 */ 771 772 where = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL); 773 xc_wait(where); 774 775 /* 776 * Ok, all lwps are either: 777 * 1) not in the cv code 778 * 2) sleeping on l->l_private 779 * 3) sleeping on p->p_waitcv 780 * 781 * Either way, l_private is stable until we change the lwps 782 * state to LSZOMB. 783 */ 784 785 mutex_enter(p->p_lock); 786 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 787 if (l->l_private) 788 cv_broadcast(l->l_private); 789 l->l_stat = LSZOMB; 790 } 791 cv_broadcast(&p->p_waitcv); 792 mutex_exit(p->p_lock); 793 794 /* 795 * Don't wait for lwps to exit. There's refcounting in the 796 * rumpuser sp code which makes this safe. Also, this routine 797 * should not sleep for a long time. 798 */ 799 } 800 801 int 802 rump_boot_gethowto() 803 { 804 805 return boothowto; 806 } 807 808 void 809 rump_boot_sethowto(int howto) 810 { 811 812 boothowto = howto; 813 } 814 815 int 816 rump_getversion(void) 817 { 818 819 return __NetBSD_Version__; 820 } 821 822 /* 823 * Note: may be called unscheduled. Not fully safe since no locking 824 * of allevents (currently that's not even available). 825 */ 826 void 827 rump_printevcnts() 828 { 829 struct evcnt *ev; 830 831 TAILQ_FOREACH(ev, &allevents, ev_list) 832 rumpuser_dprintf("%s / %s: %" PRIu64 "\n", 833 ev->ev_group, ev->ev_name, ev->ev_count); 834 } 835 836 /* 837 * If you use this interface ... well ... all bets are off. 838 * The original purpose is for the p2k fs server library to be 839 * able to use the same pid/lid for VOPs as the host kernel. 840 */ 841 void 842 rump_allbetsareoff_setid(pid_t pid, int lid) 843 { 844 struct lwp *l = curlwp; 845 struct proc *p = l->l_proc; 846 847 l->l_lid = lid; 848 p->p_pid = pid; 849 } 850