1/* $NetBSD: rumpuser_sp.c,v 1.68 2014/12/08 00:12:03 justin Exp $ */ 2 3/* 4 * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28/* 29 * Sysproxy routines. This provides system RPC support over host sockets. 30 * The most notable limitation is that the client and server must share 31 * the same ABI. This does not mean that they have to be the same 32 * machine or that they need to run the same version of the host OS, 33 * just that they must agree on the data structures. This even *might* 34 * work correctly from one hardware architecture to another. 35 */ 36 37#include <sys/cdefs.h> 38 39#if !defined(lint) 40__RCSID("$NetBSD: rumpuser_sp.c,v 1.68 2014/12/08 00:12:03 justin Exp $"); 41#endif /* !lint */ 42 43#include <sys/types.h> 44#include <sys/mman.h> 45#include <sys/socket.h> 46 47#include <arpa/inet.h> 48#include <netinet/in.h> 49#include <netinet/tcp.h> 50 51#include <assert.h> 52#include <errno.h> 53#include <fcntl.h> 54#include <poll.h> 55#include <pthread.h> 56#include <stdarg.h> 57#include <stdio.h> 58#include <stdlib.h> 59#include <string.h> 60#include <unistd.h> 61 62#include <rump/rump.h> /* XXX: for rfork flags */ 63#define LIBRUMPUSER /* XXX */ 64#include <rump/rumpuser.h> 65 66extern struct rumpuser_hyperup rumpuser__hyp; 67 68static inline void 69rumpkern_unsched(int *nlocks, void *interlock) 70{ 71 72 rumpuser__hyp.hyp_backend_unschedule(0, nlocks, interlock); 73} 74 75static inline void 76rumpkern_sched(int nlocks, void *interlock) 77{ 78 79 rumpuser__hyp.hyp_backend_schedule(nlocks, interlock); 80} 81 82#define ET(x) return(x); 83 84/* $NetBSD: sp_common.c,v 1.38 2014/01/08 01:45:29 pooka Exp $ */ 85 86/* 87 * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. 88 * 89 * Redistribution and use in source and binary forms, with or without 90 * modification, are permitted provided that the following conditions 91 * are met: 92 * 1. Redistributions of source code must retain the above copyright 93 * notice, this list of conditions and the following disclaimer. 94 * 2. Redistributions in binary form must reproduce the above copyright 95 * notice, this list of conditions and the following disclaimer in the 96 * documentation and/or other materials provided with the distribution. 97 * 98 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 99 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 100 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 101 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 102 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 103 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 104 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 105 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 106 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 107 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 108 * SUCH DAMAGE. 109 */ 110 111/* 112 * Common client/server sysproxy routines. #included. 113 */ 114 115#include <sys/types.h> 116#include <sys/mman.h> 117#include <sys/queue.h> 118#include <sys/socket.h> 119#include <sys/un.h> 120#include <sys/uio.h> 121 122#include <arpa/inet.h> 123#include <netinet/in.h> 124#include <netinet/tcp.h> 125 126#include <assert.h> 127#include <errno.h> 128#include <fcntl.h> 129#include <inttypes.h> 130#include <limits.h> 131#include <poll.h> 132#include <pthread.h> 133#include <stdarg.h> 134#include <stddef.h> 135#include <stdio.h> 136#include <stdlib.h> 137#include <string.h> 138#include <unistd.h> 139 140//#define DEBUG 141#ifdef DEBUG 142#define DPRINTF(x) mydprintf x 143static void 144mydprintf(const char *fmt, ...) 145{ 146 va_list ap; 147 148 va_start(ap, fmt); 149 vfprintf(stderr, fmt, ap); 150 va_end(ap); 151} 152#else 153#define DPRINTF(x) 154#endif 155 156#ifndef HOSTOPS 157#define host_poll poll 158#define host_read read 159#define host_sendmsg sendmsg 160#define host_setsockopt setsockopt 161#endif 162 163#define IOVPUT(_io_, _b_) _io_.iov_base = \ 164 (void *)&_b_; _io_.iov_len = sizeof(_b_); 165#define IOVPUT_WITHSIZE(_io_, _b_, _l_) _io_.iov_base = \ 166 (void *)(_b_); _io_.iov_len = _l_; 167#define SENDIOV(_spc_, _iov_) dosend(_spc_, _iov_, __arraycount(_iov_)) 168 169static int lwproc_newlwp(pid_t); 170static struct lwp *lwproc_curlwp(void); 171static void lwproc_release(void); 172static void lwproc_switch(struct lwp *); 173 174/* 175 * Bah, I hate writing on-off-wire conversions in C 176 */ 177 178enum { RUMPSP_REQ, RUMPSP_RESP, RUMPSP_ERROR }; 179enum { RUMPSP_HANDSHAKE, 180 RUMPSP_SYSCALL, 181 RUMPSP_COPYIN, RUMPSP_COPYINSTR, 182 RUMPSP_COPYOUT, RUMPSP_COPYOUTSTR, 183 RUMPSP_ANONMMAP, 184 RUMPSP_PREFORK, 185 RUMPSP_RAISE }; 186 187enum { HANDSHAKE_GUEST, HANDSHAKE_AUTH, HANDSHAKE_FORK, HANDSHAKE_EXEC }; 188 189/* 190 * error types used for RUMPSP_ERROR 191 */ 192enum rumpsp_err { RUMPSP_ERR_NONE = 0, RUMPSP_ERR_TRYAGAIN, RUMPSP_ERR_AUTH, 193 RUMPSP_ERR_INVALID_PREFORK, RUMPSP_ERR_RFORK_FAILED, 194 RUMPSP_ERR_INEXEC, RUMPSP_ERR_NOMEM, RUMPSP_ERR_MALFORMED_REQUEST }; 195 196/* 197 * The mapping of the above types to errno. They are almost never exposed 198 * to the client after handshake (except for a server resource shortage 199 * and the client trying to be funny). This is a function instead of 200 * an array to catch missing values. Theoretically, the compiled code 201 * should be the same. 202 */ 203static int 204errmap(enum rumpsp_err error) 205{ 206 207 switch (error) { 208 /* XXX: no EAUTH on Linux */ 209 case RUMPSP_ERR_NONE: return 0; 210 case RUMPSP_ERR_AUTH: return EPERM; 211 case RUMPSP_ERR_TRYAGAIN: return EAGAIN; 212 case RUMPSP_ERR_INVALID_PREFORK: return ESRCH; 213 case RUMPSP_ERR_RFORK_FAILED: return EIO; /* got a light? */ 214 case RUMPSP_ERR_INEXEC: return EBUSY; 215 case RUMPSP_ERR_NOMEM: return ENOMEM; 216 case RUMPSP_ERR_MALFORMED_REQUEST: return EINVAL; 217 } 218 219 return -1; 220} 221 222#define AUTHLEN 4 /* 128bit fork auth */ 223 224struct rsp_hdr { 225 uint64_t rsp_len; 226 uint64_t rsp_reqno; 227 uint16_t rsp_class; 228 uint16_t rsp_type; 229 /* 230 * We want this structure 64bit-aligned for typecast fun, 231 * so might as well use the following for something. 232 */ 233 union { 234 uint32_t sysnum; 235 uint32_t error; 236 uint32_t handshake; 237 uint32_t signo; 238 } u; 239}; 240#define HDRSZ sizeof(struct rsp_hdr) 241#define rsp_sysnum u.sysnum 242#define rsp_error u.error 243#define rsp_handshake u.handshake 244#define rsp_signo u.signo 245 246#define MAXBANNER 96 247 248/* 249 * Data follows the header. We have two types of structured data. 250 */ 251 252/* copyin/copyout */ 253struct rsp_copydata { 254 size_t rcp_len; 255 void *rcp_addr; 256 uint8_t rcp_data[0]; 257}; 258 259/* syscall response */ 260struct rsp_sysresp { 261 int rsys_error; 262 register_t rsys_retval[2]; 263}; 264 265struct handshake_fork { 266 uint32_t rf_auth[4]; 267 int rf_cancel; 268}; 269 270struct respwait { 271 uint64_t rw_reqno; 272 void *rw_data; 273 size_t rw_dlen; 274 int rw_done; 275 int rw_error; 276 277 pthread_cond_t rw_cv; 278 279 TAILQ_ENTRY(respwait) rw_entries; 280}; 281 282struct prefork; 283struct spclient { 284 int spc_fd; 285 int spc_refcnt; 286 int spc_state; 287 288 pthread_mutex_t spc_mtx; 289 pthread_cond_t spc_cv; 290 291 struct lwp *spc_mainlwp; 292 pid_t spc_pid; 293 294 TAILQ_HEAD(, respwait) spc_respwait; 295 296 /* rest of the fields are zeroed upon disconnect */ 297#define SPC_ZEROFF offsetof(struct spclient, spc_pfd) 298 struct pollfd *spc_pfd; 299 300 struct rsp_hdr spc_hdr; 301 uint8_t *spc_buf; 302 size_t spc_off; 303 304 uint64_t spc_nextreq; 305 uint64_t spc_syscallreq; 306 uint64_t spc_generation; 307 int spc_ostatus, spc_istatus; 308 int spc_reconnecting; 309 int spc_inexec; 310 311 LIST_HEAD(, prefork) spc_pflist; 312}; 313#define SPCSTATUS_FREE 0 314#define SPCSTATUS_BUSY 1 315#define SPCSTATUS_WANTED 2 316 317#define SPCSTATE_NEW 0 318#define SPCSTATE_RUNNING 1 319#define SPCSTATE_DYING 2 320 321typedef int (*addrparse_fn)(const char *, struct sockaddr **, int); 322typedef int (*connecthook_fn)(int); 323typedef void (*cleanup_fn)(struct sockaddr *); 324 325static int readframe(struct spclient *); 326static void handlereq(struct spclient *); 327 328static __inline void 329spcresetbuf(struct spclient *spc) 330{ 331 332 spc->spc_buf = NULL; 333 spc->spc_off = 0; 334} 335 336static __inline void 337spcfreebuf(struct spclient *spc) 338{ 339 340 free(spc->spc_buf); 341 spcresetbuf(spc); 342} 343 344static void 345sendlockl(struct spclient *spc) 346{ 347 348 while (spc->spc_ostatus != SPCSTATUS_FREE) { 349 spc->spc_ostatus = SPCSTATUS_WANTED; 350 pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx); 351 } 352 spc->spc_ostatus = SPCSTATUS_BUSY; 353} 354 355static void __unused 356sendlock(struct spclient *spc) 357{ 358 359 pthread_mutex_lock(&spc->spc_mtx); 360 sendlockl(spc); 361 pthread_mutex_unlock(&spc->spc_mtx); 362} 363 364static void 365sendunlockl(struct spclient *spc) 366{ 367 368 if (spc->spc_ostatus == SPCSTATUS_WANTED) 369 pthread_cond_broadcast(&spc->spc_cv); 370 spc->spc_ostatus = SPCSTATUS_FREE; 371} 372 373static void 374sendunlock(struct spclient *spc) 375{ 376 377 pthread_mutex_lock(&spc->spc_mtx); 378 sendunlockl(spc); 379 pthread_mutex_unlock(&spc->spc_mtx); 380} 381 382static int 383dosend(struct spclient *spc, struct iovec *iov, size_t iovlen) 384{ 385 struct msghdr msg; 386 struct pollfd pfd; 387 ssize_t n = 0; 388 int fd = spc->spc_fd; 389 struct lwp *mylwp; 390 int error = 0; 391 392 pfd.fd = fd; 393 pfd.events = POLLOUT; 394 395 mylwp = lwproc_curlwp(); 396 lwproc_newlwp(1); 397 398 memset(&msg, 0, sizeof(msg)); 399 400 for (;;) { 401 /* not first round? poll */ 402 if (n) { 403 if (host_poll(&pfd, 1, INFTIM) == -1) { 404 if (errno == EINTR) 405 continue; 406 error = errno; 407 goto out; 408 } 409 } 410 411 msg.msg_iov = iov; 412 msg.msg_iovlen = iovlen; 413 n = host_sendmsg(fd, &msg, MSG_NOSIGNAL); 414 if (n == -1) { 415 if (errno == EPIPE) 416 error = ENOTCONN; 417 if (errno != EAGAIN) 418 error = errno; 419 if (error) 420 goto out; 421 continue; 422 } 423 if (n == 0) { 424 error = ENOTCONN; 425 goto out; 426 } 427 428 /* ok, need to adjust iovec for potential next round */ 429 while (n >= (ssize_t)iov[0].iov_len && iovlen) { 430 n -= iov[0].iov_len; 431 iov++; 432 iovlen--; 433 } 434 435 if (iovlen == 0) { 436 _DIAGASSERT(n == 0); 437 break; 438 } else { 439 iov[0].iov_base = 440 (void *)((uint8_t *)iov[0].iov_base + n); 441 iov[0].iov_len -= n; 442 } 443 } 444 445 lwproc_release(); 446 if (mylwp) 447 lwproc_switch(mylwp); 448 449 out: 450 return error; 451} 452 453static void 454doputwait(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr) 455{ 456 457 rw->rw_data = NULL; 458 rw->rw_dlen = rw->rw_done = rw->rw_error = 0; 459 pthread_cond_init(&rw->rw_cv, NULL); 460 461 pthread_mutex_lock(&spc->spc_mtx); 462 rw->rw_reqno = rhdr->rsp_reqno = spc->spc_nextreq++; 463 TAILQ_INSERT_TAIL(&spc->spc_respwait, rw, rw_entries); 464} 465 466static void __unused 467putwait_locked(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr) 468{ 469 470 doputwait(spc, rw, rhdr); 471 pthread_mutex_unlock(&spc->spc_mtx); 472} 473 474static void 475putwait(struct spclient *spc, struct respwait *rw, struct rsp_hdr *rhdr) 476{ 477 478 doputwait(spc, rw, rhdr); 479 sendlockl(spc); 480 pthread_mutex_unlock(&spc->spc_mtx); 481} 482 483static void 484dounputwait(struct spclient *spc, struct respwait *rw) 485{ 486 487 TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries); 488 pthread_mutex_unlock(&spc->spc_mtx); 489 pthread_cond_destroy(&rw->rw_cv); 490 491} 492 493static void __unused 494unputwait_locked(struct spclient *spc, struct respwait *rw) 495{ 496 497 pthread_mutex_lock(&spc->spc_mtx); 498 dounputwait(spc, rw); 499} 500 501static void 502unputwait(struct spclient *spc, struct respwait *rw) 503{ 504 505 pthread_mutex_lock(&spc->spc_mtx); 506 sendunlockl(spc); 507 508 dounputwait(spc, rw); 509} 510 511static void 512kickwaiter(struct spclient *spc) 513{ 514 struct respwait *rw; 515 int error = 0; 516 517 pthread_mutex_lock(&spc->spc_mtx); 518 TAILQ_FOREACH(rw, &spc->spc_respwait, rw_entries) { 519 if (rw->rw_reqno == spc->spc_hdr.rsp_reqno) 520 break; 521 } 522 if (rw == NULL) { 523 DPRINTF(("no waiter found, invalid reqno %" PRIu64 "?\n", 524 spc->spc_hdr.rsp_reqno)); 525 pthread_mutex_unlock(&spc->spc_mtx); 526 spcfreebuf(spc); 527 return; 528 } 529 DPRINTF(("rump_sp: client %p woke up waiter at %p\n", spc, rw)); 530 rw->rw_data = spc->spc_buf; 531 rw->rw_done = 1; 532 rw->rw_dlen = (size_t)(spc->spc_off - HDRSZ); 533 if (spc->spc_hdr.rsp_class == RUMPSP_ERROR) { 534 error = rw->rw_error = errmap(spc->spc_hdr.rsp_error); 535 } 536 pthread_cond_signal(&rw->rw_cv); 537 pthread_mutex_unlock(&spc->spc_mtx); 538 539 if (error) 540 spcfreebuf(spc); 541 else 542 spcresetbuf(spc); 543} 544 545static void 546kickall(struct spclient *spc) 547{ 548 struct respwait *rw; 549 550 /* DIAGASSERT(mutex_owned(spc_lock)) */ 551 TAILQ_FOREACH(rw, &spc->spc_respwait, rw_entries) 552 pthread_cond_broadcast(&rw->rw_cv); 553} 554 555static int 556readframe(struct spclient *spc) 557{ 558 int fd = spc->spc_fd; 559 size_t left; 560 size_t framelen; 561 ssize_t n; 562 563 /* still reading header? */ 564 if (spc->spc_off < HDRSZ) { 565 DPRINTF(("rump_sp: readframe getting header at offset %zu\n", 566 spc->spc_off)); 567 568 left = HDRSZ - spc->spc_off; 569 /*LINTED: cast ok */ 570 n = host_read(fd, (uint8_t*)&spc->spc_hdr + spc->spc_off, left); 571 if (n == 0) { 572 return -1; 573 } 574 if (n == -1) { 575 if (errno == EAGAIN) 576 return 0; 577 return -1; 578 } 579 580 spc->spc_off += n; 581 if (spc->spc_off < HDRSZ) { 582 return 0; 583 } 584 585 /*LINTED*/ 586 framelen = spc->spc_hdr.rsp_len; 587 588 if (framelen < HDRSZ) { 589 return -1; 590 } else if (framelen == HDRSZ) { 591 return 1; 592 } 593 594 spc->spc_buf = malloc(framelen - HDRSZ); 595 if (spc->spc_buf == NULL) { 596 return -1; 597 } 598 memset(spc->spc_buf, 0, framelen - HDRSZ); 599 600 /* "fallthrough" */ 601 } else { 602 /*LINTED*/ 603 framelen = spc->spc_hdr.rsp_len; 604 } 605 606 left = framelen - spc->spc_off; 607 608 DPRINTF(("rump_sp: readframe getting body at offset %zu, left %zu\n", 609 spc->spc_off, left)); 610 611 if (left == 0) 612 return 1; 613 n = host_read(fd, spc->spc_buf + (spc->spc_off - HDRSZ), left); 614 if (n == 0) { 615 return -1; 616 } 617 if (n == -1) { 618 if (errno == EAGAIN) 619 return 0; 620 return -1; 621 } 622 spc->spc_off += n; 623 left -= n; 624 625 /* got everything? */ 626 if (left == 0) 627 return 1; 628 else 629 return 0; 630} 631 632static int 633tcp_parse(const char *addr, struct sockaddr **sa, int allow_wildcard) 634{ 635 struct sockaddr_in sin; 636 char buf[64]; 637 const char *p; 638 size_t l; 639 int port; 640 641 memset(&sin, 0, sizeof(sin)); 642 sin.sin_len = sizeof(sin); 643 sin.sin_family = AF_INET; 644 645 p = strchr(addr, ':'); 646 if (!p) { 647 fprintf(stderr, "rump_sp_tcp: missing port specifier\n"); 648 return EINVAL; 649 } 650 651 l = p - addr; 652 if (l > sizeof(buf)-1) { 653 fprintf(stderr, "rump_sp_tcp: address too long\n"); 654 return EINVAL; 655 } 656 strncpy(buf, addr, l); 657 buf[l] = '\0'; 658 659 /* special INADDR_ANY treatment */ 660 if (strcmp(buf, "*") == 0 || strcmp(buf, "0") == 0) { 661 sin.sin_addr.s_addr = INADDR_ANY; 662 } else { 663 switch (inet_pton(AF_INET, buf, &sin.sin_addr)) { 664 case 1: 665 break; 666 case 0: 667 fprintf(stderr, "rump_sp_tcp: cannot parse %s\n", buf); 668 return EINVAL; 669 case -1: 670 fprintf(stderr, "rump_sp_tcp: inet_pton failed\n"); 671 return errno; 672 default: 673 assert(/*CONSTCOND*/0); 674 return EINVAL; 675 } 676 } 677 678 if (!allow_wildcard && sin.sin_addr.s_addr == INADDR_ANY) { 679 fprintf(stderr, "rump_sp_tcp: client needs !INADDR_ANY\n"); 680 return EINVAL; 681 } 682 683 /* advance to port number & parse */ 684 p++; 685 l = strspn(p, "0123456789"); 686 if (l == 0) { 687 fprintf(stderr, "rump_sp_tcp: port now found: %s\n", p); 688 return EINVAL; 689 } 690 strncpy(buf, p, l); 691 buf[l] = '\0'; 692 693 if (*(p+l) != '/' && *(p+l) != '\0') { 694 fprintf(stderr, "rump_sp_tcp: junk at end of port: %s\n", addr); 695 return EINVAL; 696 } 697 698 port = atoi(buf); 699 if (port < 0 || port >= (1<<(8*sizeof(in_port_t)))) { 700 fprintf(stderr, "rump_sp_tcp: port %d out of range\n", port); 701 return ERANGE; 702 } 703 sin.sin_port = htons(port); 704 705 *sa = malloc(sizeof(sin)); 706 if (*sa == NULL) 707 return errno; 708 memcpy(*sa, &sin, sizeof(sin)); 709 return 0; 710} 711 712static int 713tcp_connecthook(int s) 714{ 715 int x; 716 717 x = 1; 718 host_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x)); 719 720 return 0; 721} 722 723static char parsedurl[256]; 724 725/*ARGSUSED*/ 726static int 727unix_parse(const char *addr, struct sockaddr **sa, int allow_wildcard) 728{ 729 struct sockaddr_un s_un; 730 size_t slen; 731 int savepath = 0; 732 733 if (strlen(addr) >= sizeof(s_un.sun_path)) 734 return ENAMETOOLONG; 735 736 /* 737 * The pathname can be all kinds of spaghetti elementals, 738 * so meek and obidient we accept everything. However, use 739 * full path for easy cleanup in case someone gives a relative 740 * one and the server does a chdir() between now than the 741 * cleanup. 742 */ 743 memset(&s_un, 0, sizeof(s_un)); 744 s_un.sun_family = AF_LOCAL; 745 if (*addr != '/') { 746 char mywd[PATH_MAX]; 747 748 if (getcwd(mywd, sizeof(mywd)) == NULL) { 749 fprintf(stderr, "warning: cannot determine cwd, " 750 "omitting socket cleanup\n"); 751 } else { 752 if (strlen(addr)+strlen(mywd)+1 753 >= sizeof(s_un.sun_path)) 754 return ENAMETOOLONG; 755 strcpy(s_un.sun_path, mywd); 756 strcat(s_un.sun_path, "/"); 757 savepath = 1; 758 } 759 } 760 strcat(s_un.sun_path, addr); 761#if defined(__linux__) || defined(__sun__) || defined(__CYGWIN__) 762 slen = sizeof(s_un); 763#else 764 s_un.sun_len = SUN_LEN(&s_un); 765 slen = s_un.sun_len+1; /* get the 0 too */ 766#endif 767 768 if (savepath && *parsedurl == '\0') { 769 snprintf(parsedurl, sizeof(parsedurl), 770 "unix://%s", s_un.sun_path); 771 } 772 773 *sa = malloc(slen); 774 if (*sa == NULL) 775 return errno; 776 memcpy(*sa, &s_un, slen); 777 778 return 0; 779} 780 781static void 782unix_cleanup(struct sockaddr *sa) 783{ 784 struct sockaddr_un *s_sun = (void *)sa; 785 786 /* 787 * cleanup only absolute paths. see unix_parse() above 788 */ 789 if (*s_sun->sun_path == '/') { 790 unlink(s_sun->sun_path); 791 } 792} 793 794/*ARGSUSED*/ 795static int 796notsupp(void) 797{ 798 799 fprintf(stderr, "rump_sp: support not yet implemented\n"); 800 return EOPNOTSUPP; 801} 802 803static int 804success(void) 805{ 806 807 return 0; 808} 809 810static struct { 811 const char *id; 812 int domain; 813 socklen_t slen; 814 addrparse_fn ap; 815 connecthook_fn connhook; 816 cleanup_fn cleanup; 817} parsetab[] = { 818 { "tcp", PF_INET, sizeof(struct sockaddr_in), 819 tcp_parse, tcp_connecthook, (cleanup_fn)success }, 820 { "unix", PF_LOCAL, sizeof(struct sockaddr_un), 821 unix_parse, (connecthook_fn)success, unix_cleanup }, 822 { "tcp6", PF_INET6, sizeof(struct sockaddr_in6), 823 (addrparse_fn)notsupp, (connecthook_fn)success, 824 (cleanup_fn)success }, 825}; 826#define NPARSE (sizeof(parsetab)/sizeof(parsetab[0])) 827 828static int 829parseurl(const char *url, struct sockaddr **sap, unsigned *idxp, 830 int allow_wildcard) 831{ 832 char id[16]; 833 const char *p, *p2; 834 size_t l; 835 unsigned i; 836 int error; 837 838 /* 839 * Parse the url 840 */ 841 842 p = url; 843 p2 = strstr(p, "://"); 844 if (!p2) { 845 fprintf(stderr, "rump_sp: invalid locator ``%s''\n", p); 846 return EINVAL; 847 } 848 l = p2-p; 849 if (l > sizeof(id)-1) { 850 fprintf(stderr, "rump_sp: identifier too long in ``%s''\n", p); 851 return EINVAL; 852 } 853 854 strncpy(id, p, l); 855 id[l] = '\0'; 856 p2 += 3; /* beginning of address */ 857 858 for (i = 0; i < NPARSE; i++) { 859 if (strcmp(id, parsetab[i].id) == 0) { 860 error = parsetab[i].ap(p2, sap, allow_wildcard); 861 if (error) 862 return error; 863 break; 864 } 865 } 866 if (i == NPARSE) { 867 fprintf(stderr, "rump_sp: invalid identifier ``%s''\n", p); 868 return EINVAL; 869 } 870 871 *idxp = i; 872 return 0; 873} 874 875#ifndef MAXCLI 876#define MAXCLI 256 877#endif 878#ifndef MAXWORKER 879#define MAXWORKER 128 880#endif 881#ifndef IDLEWORKER 882#define IDLEWORKER 16 883#endif 884int rumpsp_maxworker = MAXWORKER; 885int rumpsp_idleworker = IDLEWORKER; 886 887static struct pollfd pfdlist[MAXCLI]; 888static struct spclient spclist[MAXCLI]; 889static unsigned int disco; 890static volatile int spfini; 891 892static char banner[MAXBANNER]; 893 894#define PROTOMAJOR 0 895#define PROTOMINOR 4 896 897 898/* how to use atomic ops on Linux? */ 899#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__OpenBSD__) 900static pthread_mutex_t discomtx = PTHREAD_MUTEX_INITIALIZER; 901 902static void 903signaldisco(void) 904{ 905 906 pthread_mutex_lock(&discomtx); 907 disco++; 908 pthread_mutex_unlock(&discomtx); 909} 910 911static unsigned int 912getdisco(void) 913{ 914 unsigned int discocnt; 915 916 pthread_mutex_lock(&discomtx); 917 discocnt = disco; 918 disco = 0; 919 pthread_mutex_unlock(&discomtx); 920 921 return discocnt; 922} 923 924#elif defined(__FreeBSD__) || defined(__DragonFly__) 925 926#include <machine/atomic.h> 927#define signaldisco() atomic_add_int(&disco, 1) 928#define getdisco() atomic_readandclear_int(&disco) 929 930#else /* NetBSD */ 931 932#include <sys/atomic.h> 933#define signaldisco() atomic_inc_uint(&disco) 934#define getdisco() atomic_swap_uint(&disco, 0) 935 936#endif 937 938 939struct prefork { 940 uint32_t pf_auth[AUTHLEN]; 941 struct lwp *pf_lwp; 942 943 LIST_ENTRY(prefork) pf_entries; /* global list */ 944 LIST_ENTRY(prefork) pf_spcentries; /* linked from forking spc */ 945}; 946static LIST_HEAD(, prefork) preforks = LIST_HEAD_INITIALIZER(preforks); 947static pthread_mutex_t pfmtx; 948 949/* 950 * This version is for the server. It's optimized for multiple threads 951 * and is *NOT* reentrant wrt to signals. 952 */ 953static int 954waitresp(struct spclient *spc, struct respwait *rw) 955{ 956 int spcstate; 957 int rv = 0; 958 959 pthread_mutex_lock(&spc->spc_mtx); 960 sendunlockl(spc); 961 while (!rw->rw_done && spc->spc_state != SPCSTATE_DYING) { 962 pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx); 963 } 964 TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries); 965 spcstate = spc->spc_state; 966 pthread_mutex_unlock(&spc->spc_mtx); 967 968 pthread_cond_destroy(&rw->rw_cv); 969 970 if (rv) 971 return rv; 972 if (spcstate == SPCSTATE_DYING) 973 return ENOTCONN; 974 return rw->rw_error; 975} 976 977/* 978 * Manual wrappers, since librump does not have access to the 979 * user namespace wrapped interfaces. 980 */ 981 982static void 983lwproc_switch(struct lwp *l) 984{ 985 986 rumpuser__hyp.hyp_schedule(); 987 rumpuser__hyp.hyp_lwproc_switch(l); 988 rumpuser__hyp.hyp_unschedule(); 989} 990 991static void 992lwproc_release(void) 993{ 994 995 rumpuser__hyp.hyp_schedule(); 996 rumpuser__hyp.hyp_lwproc_release(); 997 rumpuser__hyp.hyp_unschedule(); 998} 999 1000static int 1001lwproc_rfork(struct spclient *spc, int flags, const char *comm) 1002{ 1003 int rv; 1004 1005 rumpuser__hyp.hyp_schedule(); 1006 rv = rumpuser__hyp.hyp_lwproc_rfork(spc, flags, comm); 1007 rumpuser__hyp.hyp_unschedule(); 1008 1009 return rv; 1010} 1011 1012static int 1013lwproc_newlwp(pid_t pid) 1014{ 1015 int rv; 1016 1017 rumpuser__hyp.hyp_schedule(); 1018 rv = rumpuser__hyp.hyp_lwproc_newlwp(pid); 1019 rumpuser__hyp.hyp_unschedule(); 1020 1021 return rv; 1022} 1023 1024static struct lwp * 1025lwproc_curlwp(void) 1026{ 1027 struct lwp *l; 1028 1029 rumpuser__hyp.hyp_schedule(); 1030 l = rumpuser__hyp.hyp_lwproc_curlwp(); 1031 rumpuser__hyp.hyp_unschedule(); 1032 1033 return l; 1034} 1035 1036static pid_t 1037lwproc_getpid(void) 1038{ 1039 pid_t p; 1040 1041 rumpuser__hyp.hyp_schedule(); 1042 p = rumpuser__hyp.hyp_getpid(); 1043 rumpuser__hyp.hyp_unschedule(); 1044 1045 return p; 1046} 1047 1048static void 1049lwproc_execnotify(const char *comm) 1050{ 1051 1052 rumpuser__hyp.hyp_schedule(); 1053 rumpuser__hyp.hyp_execnotify(comm); 1054 rumpuser__hyp.hyp_unschedule(); 1055} 1056 1057static void 1058lwproc_lwpexit(void) 1059{ 1060 1061 rumpuser__hyp.hyp_schedule(); 1062 rumpuser__hyp.hyp_lwpexit(); 1063 rumpuser__hyp.hyp_unschedule(); 1064} 1065 1066static int 1067rumpsyscall(int sysnum, void *data, register_t *regrv) 1068{ 1069 long retval[2] = {0, 0}; 1070 int rv; 1071 1072 rumpuser__hyp.hyp_schedule(); 1073 rv = rumpuser__hyp.hyp_syscall(sysnum, data, retval); 1074 rumpuser__hyp.hyp_unschedule(); 1075 1076 regrv[0] = retval[0]; 1077 regrv[1] = retval[1]; 1078 return rv; 1079} 1080 1081static uint64_t 1082nextreq(struct spclient *spc) 1083{ 1084 uint64_t nw; 1085 1086 pthread_mutex_lock(&spc->spc_mtx); 1087 nw = spc->spc_nextreq++; 1088 pthread_mutex_unlock(&spc->spc_mtx); 1089 1090 return nw; 1091} 1092 1093/* 1094 * XXX: we send responses with "blocking" I/O. This is not 1095 * ok for the main thread. XXXFIXME 1096 */ 1097 1098static void 1099send_error_resp(struct spclient *spc, uint64_t reqno, enum rumpsp_err error) 1100{ 1101 struct rsp_hdr rhdr; 1102 struct iovec iov[1]; 1103 1104 rhdr.rsp_len = sizeof(rhdr); 1105 rhdr.rsp_reqno = reqno; 1106 rhdr.rsp_class = RUMPSP_ERROR; 1107 rhdr.rsp_type = 0; 1108 rhdr.rsp_error = error; 1109 1110 IOVPUT(iov[0], rhdr); 1111 1112 sendlock(spc); 1113 (void)SENDIOV(spc, iov); 1114 sendunlock(spc); 1115} 1116 1117static int 1118send_handshake_resp(struct spclient *spc, uint64_t reqno, int error) 1119{ 1120 struct rsp_hdr rhdr; 1121 struct iovec iov[2]; 1122 int rv; 1123 1124 rhdr.rsp_len = sizeof(rhdr) + sizeof(error); 1125 rhdr.rsp_reqno = reqno; 1126 rhdr.rsp_class = RUMPSP_RESP; 1127 rhdr.rsp_type = RUMPSP_HANDSHAKE; 1128 rhdr.rsp_error = 0; 1129 1130 IOVPUT(iov[0], rhdr); 1131 IOVPUT(iov[1], error); 1132 1133 sendlock(spc); 1134 rv = SENDIOV(spc, iov); 1135 sendunlock(spc); 1136 1137 return rv; 1138} 1139 1140static int 1141send_syscall_resp(struct spclient *spc, uint64_t reqno, int error, 1142 register_t *retval) 1143{ 1144 struct rsp_hdr rhdr; 1145 struct rsp_sysresp sysresp; 1146 struct iovec iov[2]; 1147 int rv; 1148 1149 rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp); 1150 rhdr.rsp_reqno = reqno; 1151 rhdr.rsp_class = RUMPSP_RESP; 1152 rhdr.rsp_type = RUMPSP_SYSCALL; 1153 rhdr.rsp_sysnum = 0; 1154 1155 sysresp.rsys_error = error; 1156 memcpy(sysresp.rsys_retval, retval, sizeof(sysresp.rsys_retval)); 1157 1158 IOVPUT(iov[0], rhdr); 1159 IOVPUT(iov[1], sysresp); 1160 1161 sendlock(spc); 1162 rv = SENDIOV(spc, iov); 1163 sendunlock(spc); 1164 1165 return rv; 1166} 1167 1168static int 1169send_prefork_resp(struct spclient *spc, uint64_t reqno, uint32_t *auth) 1170{ 1171 struct rsp_hdr rhdr; 1172 struct iovec iov[2]; 1173 int rv; 1174 1175 rhdr.rsp_len = sizeof(rhdr) + AUTHLEN*sizeof(*auth); 1176 rhdr.rsp_reqno = reqno; 1177 rhdr.rsp_class = RUMPSP_RESP; 1178 rhdr.rsp_type = RUMPSP_PREFORK; 1179 rhdr.rsp_sysnum = 0; 1180 1181 IOVPUT(iov[0], rhdr); 1182 IOVPUT_WITHSIZE(iov[1], auth, AUTHLEN*sizeof(*auth)); 1183 1184 sendlock(spc); 1185 rv = SENDIOV(spc, iov); 1186 sendunlock(spc); 1187 1188 return rv; 1189} 1190 1191static int 1192copyin_req(struct spclient *spc, const void *remaddr, size_t *dlen, 1193 int wantstr, void **resp) 1194{ 1195 struct rsp_hdr rhdr; 1196 struct rsp_copydata copydata; 1197 struct respwait rw; 1198 struct iovec iov[2]; 1199 int rv; 1200 1201 DPRINTF(("copyin_req: %zu bytes from %p\n", *dlen, remaddr)); 1202 1203 rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata); 1204 rhdr.rsp_class = RUMPSP_REQ; 1205 if (wantstr) 1206 rhdr.rsp_type = RUMPSP_COPYINSTR; 1207 else 1208 rhdr.rsp_type = RUMPSP_COPYIN; 1209 rhdr.rsp_sysnum = 0; 1210 1211 copydata.rcp_addr = __UNCONST(remaddr); 1212 copydata.rcp_len = *dlen; 1213 1214 IOVPUT(iov[0], rhdr); 1215 IOVPUT(iov[1], copydata); 1216 1217 putwait(spc, &rw, &rhdr); 1218 rv = SENDIOV(spc, iov); 1219 if (rv) { 1220 unputwait(spc, &rw); 1221 return rv; 1222 } 1223 1224 rv = waitresp(spc, &rw); 1225 1226 DPRINTF(("copyin: response %d\n", rv)); 1227 1228 *resp = rw.rw_data; 1229 if (wantstr) 1230 *dlen = rw.rw_dlen; 1231 1232 return rv; 1233 1234} 1235 1236static int 1237send_copyout_req(struct spclient *spc, const void *remaddr, 1238 const void *data, size_t dlen) 1239{ 1240 struct rsp_hdr rhdr; 1241 struct rsp_copydata copydata; 1242 struct iovec iov[3]; 1243 int rv; 1244 1245 DPRINTF(("copyout_req (async): %zu bytes to %p\n", dlen, remaddr)); 1246 1247 rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen; 1248 rhdr.rsp_reqno = nextreq(spc); 1249 rhdr.rsp_class = RUMPSP_REQ; 1250 rhdr.rsp_type = RUMPSP_COPYOUT; 1251 rhdr.rsp_sysnum = 0; 1252 1253 copydata.rcp_addr = __UNCONST(remaddr); 1254 copydata.rcp_len = dlen; 1255 1256 IOVPUT(iov[0], rhdr); 1257 IOVPUT(iov[1], copydata); 1258 IOVPUT_WITHSIZE(iov[2], __UNCONST(data), dlen); 1259 1260 sendlock(spc); 1261 rv = SENDIOV(spc, iov); 1262 sendunlock(spc); 1263 1264 return rv; 1265} 1266 1267static int 1268anonmmap_req(struct spclient *spc, size_t howmuch, void **resp) 1269{ 1270 struct rsp_hdr rhdr; 1271 struct respwait rw; 1272 struct iovec iov[2]; 1273 int rv; 1274 1275 DPRINTF(("anonmmap_req: %zu bytes\n", howmuch)); 1276 1277 rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch); 1278 rhdr.rsp_class = RUMPSP_REQ; 1279 rhdr.rsp_type = RUMPSP_ANONMMAP; 1280 rhdr.rsp_sysnum = 0; 1281 1282 IOVPUT(iov[0], rhdr); 1283 IOVPUT(iov[1], howmuch); 1284 1285 putwait(spc, &rw, &rhdr); 1286 rv = SENDIOV(spc, iov); 1287 if (rv) { 1288 unputwait(spc, &rw); 1289 return rv; 1290 } 1291 1292 rv = waitresp(spc, &rw); 1293 1294 *resp = rw.rw_data; 1295 1296 DPRINTF(("anonmmap: mapped at %p\n", **(void ***)resp)); 1297 1298 return rv; 1299} 1300 1301static int 1302send_raise_req(struct spclient *spc, int signo) 1303{ 1304 struct rsp_hdr rhdr; 1305 struct iovec iov[1]; 1306 int rv; 1307 1308 rhdr.rsp_len = sizeof(rhdr); 1309 rhdr.rsp_class = RUMPSP_REQ; 1310 rhdr.rsp_type = RUMPSP_RAISE; 1311 rhdr.rsp_signo = signo; 1312 1313 IOVPUT(iov[0], rhdr); 1314 1315 sendlock(spc); 1316 rv = SENDIOV(spc, iov); 1317 sendunlock(spc); 1318 1319 return rv; 1320} 1321 1322static void 1323spcref(struct spclient *spc) 1324{ 1325 1326 pthread_mutex_lock(&spc->spc_mtx); 1327 spc->spc_refcnt++; 1328 pthread_mutex_unlock(&spc->spc_mtx); 1329} 1330 1331static void 1332spcrelease(struct spclient *spc) 1333{ 1334 int ref; 1335 1336 pthread_mutex_lock(&spc->spc_mtx); 1337 ref = --spc->spc_refcnt; 1338 if (__predict_false(spc->spc_inexec && ref <= 2)) 1339 pthread_cond_broadcast(&spc->spc_cv); 1340 pthread_mutex_unlock(&spc->spc_mtx); 1341 1342 if (ref > 0) 1343 return; 1344 1345 DPRINTF(("rump_sp: spcrelease: spc %p fd %d\n", spc, spc->spc_fd)); 1346 1347 _DIAGASSERT(TAILQ_EMPTY(&spc->spc_respwait)); 1348 _DIAGASSERT(spc->spc_buf == NULL); 1349 1350 if (spc->spc_mainlwp) { 1351 lwproc_switch(spc->spc_mainlwp); 1352 lwproc_release(); 1353 } 1354 spc->spc_mainlwp = NULL; 1355 1356 close(spc->spc_fd); 1357 spc->spc_fd = -1; 1358 spc->spc_state = SPCSTATE_NEW; 1359 1360 signaldisco(); 1361} 1362 1363static void 1364serv_handledisco(unsigned int idx) 1365{ 1366 struct spclient *spc = &spclist[idx]; 1367 int dolwpexit; 1368 1369 DPRINTF(("rump_sp: disconnecting [%u]\n", idx)); 1370 1371 pfdlist[idx].fd = -1; 1372 pfdlist[idx].revents = 0; 1373 pthread_mutex_lock(&spc->spc_mtx); 1374 spc->spc_state = SPCSTATE_DYING; 1375 kickall(spc); 1376 sendunlockl(spc); 1377 /* exec uses mainlwp in another thread, but also nuked all lwps */ 1378 dolwpexit = !spc->spc_inexec; 1379 pthread_mutex_unlock(&spc->spc_mtx); 1380 1381 if (dolwpexit && spc->spc_mainlwp) { 1382 lwproc_switch(spc->spc_mainlwp); 1383 lwproc_lwpexit(); 1384 lwproc_switch(NULL); 1385 } 1386 1387 /* 1388 * Nobody's going to attempt to send/receive anymore, 1389 * so reinit info relevant to that. 1390 */ 1391 /*LINTED:pointer casts may be ok*/ 1392 memset((char *)spc + SPC_ZEROFF, 0, sizeof(*spc) - SPC_ZEROFF); 1393 1394 spcrelease(spc); 1395} 1396 1397static void 1398serv_shutdown(void) 1399{ 1400 struct spclient *spc; 1401 unsigned int i; 1402 1403 for (i = 1; i < MAXCLI; i++) { 1404 spc = &spclist[i]; 1405 if (spc->spc_fd == -1) 1406 continue; 1407 1408 shutdown(spc->spc_fd, SHUT_RDWR); 1409 serv_handledisco(i); 1410 1411 spcrelease(spc); 1412 } 1413} 1414 1415static unsigned 1416serv_handleconn(int fd, connecthook_fn connhook, int busy) 1417{ 1418 struct sockaddr_storage ss; 1419 socklen_t sl = sizeof(ss); 1420 int newfd, flags; 1421 unsigned i; 1422 1423 /*LINTED: cast ok */ 1424 newfd = accept(fd, (struct sockaddr *)&ss, &sl); 1425 if (newfd == -1) 1426 return 0; 1427 1428 if (busy) { 1429 close(newfd); /* EBUSY */ 1430 return 0; 1431 } 1432 1433 flags = fcntl(newfd, F_GETFL, 0); 1434 if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) { 1435 close(newfd); 1436 return 0; 1437 } 1438 1439 if (connhook(newfd) != 0) { 1440 close(newfd); 1441 return 0; 1442 } 1443 1444 /* write out a banner for the client */ 1445 if (send(newfd, banner, strlen(banner), MSG_NOSIGNAL) 1446 != (ssize_t)strlen(banner)) { 1447 close(newfd); 1448 return 0; 1449 } 1450 1451 /* find empty slot the simple way */ 1452 for (i = 0; i < MAXCLI; i++) { 1453 if (pfdlist[i].fd == -1 && spclist[i].spc_state == SPCSTATE_NEW) 1454 break; 1455 } 1456 1457 /* 1458 * Although not finding a slot is impossible (cf. how this routine 1459 * is called), the compiler can still think that i == MAXCLI 1460 * if this code is either compiled with NDEBUG or the platform 1461 * does not use __dead for assert(). Therefore, add an explicit 1462 * check to avoid an array-bounds error. 1463 */ 1464 /* assert(i < MAXCLI); */ 1465 if (i == MAXCLI) 1466 abort(); 1467 1468 pfdlist[i].fd = newfd; 1469 spclist[i].spc_fd = newfd; 1470 spclist[i].spc_istatus = SPCSTATUS_BUSY; /* dedicated receiver */ 1471 spclist[i].spc_refcnt = 1; 1472 1473 TAILQ_INIT(&spclist[i].spc_respwait); 1474 1475 DPRINTF(("rump_sp: added new connection fd %d at idx %u\n", newfd, i)); 1476 1477 return i; 1478} 1479 1480static void 1481serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data) 1482{ 1483 register_t retval[2] = {0, 0}; 1484 int rv, sysnum; 1485 1486 sysnum = (int)rhdr->rsp_sysnum; 1487 DPRINTF(("rump_sp: handling syscall %d from client %d\n", 1488 sysnum, spc->spc_pid)); 1489 1490 if (__predict_false((rv = lwproc_newlwp(spc->spc_pid)) != 0)) { 1491 retval[0] = -1; 1492 send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval); 1493 return; 1494 } 1495 spc->spc_syscallreq = rhdr->rsp_reqno; 1496 rv = rumpsyscall(sysnum, data, retval); 1497 spc->spc_syscallreq = 0; 1498 lwproc_release(); 1499 1500 DPRINTF(("rump_sp: got return value %d & %d/%d\n", 1501 rv, retval[0], retval[1])); 1502 1503 send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval); 1504} 1505 1506static void 1507serv_handleexec(struct spclient *spc, struct rsp_hdr *rhdr, char *comm) 1508{ 1509 size_t commlen = rhdr->rsp_len - HDRSZ; 1510 1511 pthread_mutex_lock(&spc->spc_mtx); 1512 /* one for the connection and one for us */ 1513 while (spc->spc_refcnt > 2) 1514 pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx); 1515 pthread_mutex_unlock(&spc->spc_mtx); 1516 1517 /* 1518 * ok, all the threads are dead (or one is still alive and 1519 * the connection is dead, in which case this doesn't matter 1520 * very much). proceed with exec. 1521 */ 1522 1523 /* ensure comm is 0-terminated */ 1524 /* TODO: make sure it contains sensible chars? */ 1525 comm[commlen] = '\0'; 1526 1527 lwproc_switch(spc->spc_mainlwp); 1528 lwproc_execnotify(comm); 1529 lwproc_switch(NULL); 1530 1531 pthread_mutex_lock(&spc->spc_mtx); 1532 spc->spc_inexec = 0; 1533 pthread_mutex_unlock(&spc->spc_mtx); 1534 send_handshake_resp(spc, rhdr->rsp_reqno, 0); 1535} 1536 1537enum sbatype { SBA_SYSCALL, SBA_EXEC }; 1538 1539struct servbouncearg { 1540 struct spclient *sba_spc; 1541 struct rsp_hdr sba_hdr; 1542 enum sbatype sba_type; 1543 uint8_t *sba_data; 1544 1545 TAILQ_ENTRY(servbouncearg) sba_entries; 1546}; 1547static pthread_mutex_t sbamtx; 1548static pthread_cond_t sbacv; 1549static int nworker, idleworker, nwork; 1550static TAILQ_HEAD(, servbouncearg) wrklist = TAILQ_HEAD_INITIALIZER(wrklist); 1551 1552/*ARGSUSED*/ 1553static void * 1554serv_workbouncer(void *arg) 1555{ 1556 struct servbouncearg *sba; 1557 1558 for (;;) { 1559 pthread_mutex_lock(&sbamtx); 1560 if (__predict_false(idleworker - nwork >= rumpsp_idleworker)) { 1561 nworker--; 1562 pthread_mutex_unlock(&sbamtx); 1563 break; 1564 } 1565 idleworker++; 1566 while (TAILQ_EMPTY(&wrklist)) { 1567 _DIAGASSERT(nwork == 0); 1568 pthread_cond_wait(&sbacv, &sbamtx); 1569 } 1570 idleworker--; 1571 1572 sba = TAILQ_FIRST(&wrklist); 1573 TAILQ_REMOVE(&wrklist, sba, sba_entries); 1574 nwork--; 1575 pthread_mutex_unlock(&sbamtx); 1576 1577 if (__predict_true(sba->sba_type == SBA_SYSCALL)) { 1578 serv_handlesyscall(sba->sba_spc, 1579 &sba->sba_hdr, sba->sba_data); 1580 } else { 1581 _DIAGASSERT(sba->sba_type == SBA_EXEC); 1582 serv_handleexec(sba->sba_spc, &sba->sba_hdr, 1583 (char *)sba->sba_data); 1584 } 1585 spcrelease(sba->sba_spc); 1586 free(sba->sba_data); 1587 free(sba); 1588 } 1589 1590 return NULL; 1591} 1592 1593static int 1594sp_copyin(void *arg, const void *raddr, void *laddr, size_t *len, int wantstr) 1595{ 1596 struct spclient *spc = arg; 1597 void *rdata = NULL; /* XXXuninit */ 1598 int rv, nlocks; 1599 1600 rumpkern_unsched(&nlocks, NULL); 1601 1602 rv = copyin_req(spc, raddr, len, wantstr, &rdata); 1603 if (rv) 1604 goto out; 1605 1606 memcpy(laddr, rdata, *len); 1607 free(rdata); 1608 1609 out: 1610 rumpkern_sched(nlocks, NULL); 1611 if (rv) 1612 rv = EFAULT; 1613 ET(rv); 1614} 1615 1616int 1617rumpuser_sp_copyin(void *arg, const void *raddr, void *laddr, size_t len) 1618{ 1619 int rv; 1620 1621 rv = sp_copyin(arg, raddr, laddr, &len, 0); 1622 ET(rv); 1623} 1624 1625int 1626rumpuser_sp_copyinstr(void *arg, const void *raddr, void *laddr, size_t *len) 1627{ 1628 int rv; 1629 1630 rv = sp_copyin(arg, raddr, laddr, len, 1); 1631 ET(rv); 1632} 1633 1634static int 1635sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen) 1636{ 1637 struct spclient *spc = arg; 1638 int nlocks, rv; 1639 1640 rumpkern_unsched(&nlocks, NULL); 1641 rv = send_copyout_req(spc, raddr, laddr, dlen); 1642 rumpkern_sched(nlocks, NULL); 1643 1644 if (rv) 1645 rv = EFAULT; 1646 ET(rv); 1647} 1648 1649int 1650rumpuser_sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen) 1651{ 1652 int rv; 1653 1654 rv = sp_copyout(arg, laddr, raddr, dlen); 1655 ET(rv); 1656} 1657 1658int 1659rumpuser_sp_copyoutstr(void *arg, const void *laddr, void *raddr, size_t *dlen) 1660{ 1661 int rv; 1662 1663 rv = sp_copyout(arg, laddr, raddr, *dlen); 1664 ET(rv); 1665} 1666 1667int 1668rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr) 1669{ 1670 struct spclient *spc = arg; 1671 void *resp, *rdata = NULL; /* XXXuninit */ 1672 int nlocks, rv; 1673 1674 rumpkern_unsched(&nlocks, NULL); 1675 1676 rv = anonmmap_req(spc, howmuch, &rdata); 1677 if (rv) { 1678 rv = EFAULT; 1679 goto out; 1680 } 1681 1682 resp = *(void **)rdata; 1683 free(rdata); 1684 1685 if (resp == NULL) { 1686 rv = ENOMEM; 1687 } 1688 1689 *addr = resp; 1690 1691 out: 1692 rumpkern_sched(nlocks, NULL); 1693 ET(rv); 1694} 1695 1696int 1697rumpuser_sp_raise(void *arg, int signo) 1698{ 1699 struct spclient *spc = arg; 1700 int rv, nlocks; 1701 1702 rumpkern_unsched(&nlocks, NULL); 1703 rv = send_raise_req(spc, signo); 1704 rumpkern_sched(nlocks, NULL); 1705 1706 return rv; 1707} 1708 1709static pthread_attr_t pattr_detached; 1710static void 1711schedulework(struct spclient *spc, enum sbatype sba_type) 1712{ 1713 struct servbouncearg *sba; 1714 pthread_t pt; 1715 uint64_t reqno; 1716 int retries = 0; 1717 1718 reqno = spc->spc_hdr.rsp_reqno; 1719 while ((sba = malloc(sizeof(*sba))) == NULL) { 1720 if (nworker == 0 || retries > 10) { 1721 send_error_resp(spc, reqno, RUMPSP_ERR_TRYAGAIN); 1722 spcfreebuf(spc); 1723 return; 1724 } 1725 /* slim chance of more memory? */ 1726 usleep(10000); 1727 } 1728 1729 sba->sba_spc = spc; 1730 sba->sba_type = sba_type; 1731 sba->sba_hdr = spc->spc_hdr; 1732 sba->sba_data = spc->spc_buf; 1733 spcresetbuf(spc); 1734 1735 spcref(spc); 1736 1737 pthread_mutex_lock(&sbamtx); 1738 TAILQ_INSERT_TAIL(&wrklist, sba, sba_entries); 1739 nwork++; 1740 if (nwork <= idleworker) { 1741 /* do we have a daemon's tool (i.e. idle threads)? */ 1742 pthread_cond_signal(&sbacv); 1743 } else if (nworker < rumpsp_maxworker) { 1744 /* 1745 * Else, need to create one 1746 * (if we can, otherwise just expect another 1747 * worker to pick up the syscall) 1748 */ 1749 if (pthread_create(&pt, &pattr_detached, 1750 serv_workbouncer, NULL) == 0) { 1751 nworker++; 1752 } 1753 } 1754 pthread_mutex_unlock(&sbamtx); 1755} 1756 1757/* 1758 * 1759 * Startup routines and mainloop for server. 1760 * 1761 */ 1762 1763struct spservarg { 1764 int sps_sock; 1765 connecthook_fn sps_connhook; 1766}; 1767 1768static void 1769handlereq(struct spclient *spc) 1770{ 1771 uint64_t reqno; 1772 int error; 1773 1774 reqno = spc->spc_hdr.rsp_reqno; 1775 if (__predict_false(spc->spc_state == SPCSTATE_NEW)) { 1776 if (spc->spc_hdr.rsp_type != RUMPSP_HANDSHAKE) { 1777 send_error_resp(spc, reqno, RUMPSP_ERR_AUTH); 1778 shutdown(spc->spc_fd, SHUT_RDWR); 1779 spcfreebuf(spc); 1780 return; 1781 } 1782 1783 if (spc->spc_hdr.rsp_handshake == HANDSHAKE_GUEST) { 1784 char *comm = (char *)spc->spc_buf; 1785 size_t commlen = spc->spc_hdr.rsp_len - HDRSZ; 1786 1787 /* ensure it's 0-terminated */ 1788 /* XXX make sure it contains sensible chars? */ 1789 comm[commlen] = '\0'; 1790 1791 /* make sure we fork off of proc1 */ 1792 _DIAGASSERT(lwproc_curlwp() == NULL); 1793 1794 if ((error = lwproc_rfork(spc, 1795 RUMP_RFFD_CLEAR, comm)) != 0) { 1796 shutdown(spc->spc_fd, SHUT_RDWR); 1797 } 1798 1799 spcfreebuf(spc); 1800 if (error) 1801 return; 1802 1803 spc->spc_mainlwp = lwproc_curlwp(); 1804 1805 send_handshake_resp(spc, reqno, 0); 1806 } else if (spc->spc_hdr.rsp_handshake == HANDSHAKE_FORK) { 1807 struct lwp *tmpmain; 1808 struct prefork *pf; 1809 struct handshake_fork *rfp; 1810 int cancel; 1811 1812 if (spc->spc_off-HDRSZ != sizeof(*rfp)) { 1813 send_error_resp(spc, reqno, 1814 RUMPSP_ERR_MALFORMED_REQUEST); 1815 shutdown(spc->spc_fd, SHUT_RDWR); 1816 spcfreebuf(spc); 1817 return; 1818 } 1819 1820 /*LINTED*/ 1821 rfp = (void *)spc->spc_buf; 1822 cancel = rfp->rf_cancel; 1823 1824 pthread_mutex_lock(&pfmtx); 1825 LIST_FOREACH(pf, &preforks, pf_entries) { 1826 if (memcmp(rfp->rf_auth, pf->pf_auth, 1827 sizeof(rfp->rf_auth)) == 0) { 1828 LIST_REMOVE(pf, pf_entries); 1829 LIST_REMOVE(pf, pf_spcentries); 1830 break; 1831 } 1832 } 1833 pthread_mutex_unlock(&pfmtx); 1834 spcfreebuf(spc); 1835 1836 if (!pf) { 1837 send_error_resp(spc, reqno, 1838 RUMPSP_ERR_INVALID_PREFORK); 1839 shutdown(spc->spc_fd, SHUT_RDWR); 1840 return; 1841 } 1842 1843 tmpmain = pf->pf_lwp; 1844 free(pf); 1845 lwproc_switch(tmpmain); 1846 if (cancel) { 1847 lwproc_release(); 1848 shutdown(spc->spc_fd, SHUT_RDWR); 1849 return; 1850 } 1851 1852 /* 1853 * So, we forked already during "prefork" to save 1854 * the file descriptors from a parent exit 1855 * race condition. But now we need to fork 1856 * a second time since the initial fork has 1857 * the wrong spc pointer. (yea, optimize 1858 * interfaces some day if anyone cares) 1859 */ 1860 if ((error = lwproc_rfork(spc, 1861 RUMP_RFFD_SHARE, NULL)) != 0) { 1862 send_error_resp(spc, reqno, 1863 RUMPSP_ERR_RFORK_FAILED); 1864 shutdown(spc->spc_fd, SHUT_RDWR); 1865 lwproc_release(); 1866 return; 1867 } 1868 spc->spc_mainlwp = lwproc_curlwp(); 1869 lwproc_switch(tmpmain); 1870 lwproc_release(); 1871 lwproc_switch(spc->spc_mainlwp); 1872 1873 send_handshake_resp(spc, reqno, 0); 1874 } else { 1875 send_error_resp(spc, reqno, RUMPSP_ERR_AUTH); 1876 shutdown(spc->spc_fd, SHUT_RDWR); 1877 spcfreebuf(spc); 1878 return; 1879 } 1880 1881 spc->spc_pid = lwproc_getpid(); 1882 1883 DPRINTF(("rump_sp: handshake for client %p complete, pid %d\n", 1884 spc, spc->spc_pid)); 1885 1886 lwproc_switch(NULL); 1887 spc->spc_state = SPCSTATE_RUNNING; 1888 return; 1889 } 1890 1891 if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_PREFORK)) { 1892 struct prefork *pf; 1893 uint32_t auth[AUTHLEN]; 1894 size_t randlen; 1895 int inexec; 1896 1897 DPRINTF(("rump_sp: prefork handler executing for %p\n", spc)); 1898 spcfreebuf(spc); 1899 1900 pthread_mutex_lock(&spc->spc_mtx); 1901 inexec = spc->spc_inexec; 1902 pthread_mutex_unlock(&spc->spc_mtx); 1903 if (inexec) { 1904 send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC); 1905 shutdown(spc->spc_fd, SHUT_RDWR); 1906 return; 1907 } 1908 1909 pf = malloc(sizeof(*pf)); 1910 if (pf == NULL) { 1911 send_error_resp(spc, reqno, RUMPSP_ERR_NOMEM); 1912 return; 1913 } 1914 1915 /* 1916 * Use client main lwp to fork. this is never used by 1917 * worker threads (except in exec, but we checked for that 1918 * above) so we can safely use it here. 1919 */ 1920 lwproc_switch(spc->spc_mainlwp); 1921 if ((error = lwproc_rfork(spc, RUMP_RFFD_COPY, NULL)) != 0) { 1922 DPRINTF(("rump_sp: fork failed: %d (%p)\n",error, spc)); 1923 send_error_resp(spc, reqno, RUMPSP_ERR_RFORK_FAILED); 1924 lwproc_switch(NULL); 1925 free(pf); 1926 return; 1927 } 1928 1929 /* Ok, we have a new process context and a new curlwp */ 1930 rumpuser_getrandom(auth, sizeof(auth), 0, &randlen); 1931 memcpy(pf->pf_auth, auth, sizeof(pf->pf_auth)); 1932 pf->pf_lwp = lwproc_curlwp(); 1933 lwproc_switch(NULL); 1934 1935 pthread_mutex_lock(&pfmtx); 1936 LIST_INSERT_HEAD(&preforks, pf, pf_entries); 1937 LIST_INSERT_HEAD(&spc->spc_pflist, pf, pf_spcentries); 1938 pthread_mutex_unlock(&pfmtx); 1939 1940 DPRINTF(("rump_sp: prefork handler success %p\n", spc)); 1941 1942 send_prefork_resp(spc, reqno, auth); 1943 return; 1944 } 1945 1946 if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_HANDSHAKE)) { 1947 int inexec; 1948 1949 if (spc->spc_hdr.rsp_handshake != HANDSHAKE_EXEC) { 1950 send_error_resp(spc, reqno, 1951 RUMPSP_ERR_MALFORMED_REQUEST); 1952 shutdown(spc->spc_fd, SHUT_RDWR); 1953 spcfreebuf(spc); 1954 return; 1955 } 1956 1957 pthread_mutex_lock(&spc->spc_mtx); 1958 inexec = spc->spc_inexec; 1959 pthread_mutex_unlock(&spc->spc_mtx); 1960 if (inexec) { 1961 send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC); 1962 shutdown(spc->spc_fd, SHUT_RDWR); 1963 spcfreebuf(spc); 1964 return; 1965 } 1966 1967 pthread_mutex_lock(&spc->spc_mtx); 1968 spc->spc_inexec = 1; 1969 pthread_mutex_unlock(&spc->spc_mtx); 1970 1971 /* 1972 * start to drain lwps. we will wait for it to finish 1973 * in another thread 1974 */ 1975 lwproc_switch(spc->spc_mainlwp); 1976 lwproc_lwpexit(); 1977 lwproc_switch(NULL); 1978 1979 /* 1980 * exec has to wait for lwps to drain, so finish it off 1981 * in another thread 1982 */ 1983 schedulework(spc, SBA_EXEC); 1984 return; 1985 } 1986 1987 if (__predict_false(spc->spc_hdr.rsp_type != RUMPSP_SYSCALL)) { 1988 send_error_resp(spc, reqno, RUMPSP_ERR_MALFORMED_REQUEST); 1989 spcfreebuf(spc); 1990 return; 1991 } 1992 1993 schedulework(spc, SBA_SYSCALL); 1994} 1995 1996static void * 1997spserver(void *arg) 1998{ 1999 struct spservarg *sarg = arg; 2000 struct spclient *spc; 2001 unsigned idx; 2002 int seen; 2003 int rv; 2004 unsigned int nfds, maxidx; 2005 2006 for (idx = 0; idx < MAXCLI; idx++) { 2007 pfdlist[idx].fd = -1; 2008 pfdlist[idx].events = POLLIN; 2009 2010 spc = &spclist[idx]; 2011 pthread_mutex_init(&spc->spc_mtx, NULL); 2012 pthread_cond_init(&spc->spc_cv, NULL); 2013 spc->spc_fd = -1; 2014 } 2015 pfdlist[0].fd = spclist[0].spc_fd = sarg->sps_sock; 2016 pfdlist[0].events = POLLIN; 2017 nfds = 1; 2018 maxidx = 0; 2019 2020 pthread_attr_init(&pattr_detached); 2021 pthread_attr_setdetachstate(&pattr_detached, PTHREAD_CREATE_DETACHED); 2022#if NOTYET 2023 pthread_attr_setstacksize(&pattr_detached, 32*1024); 2024#endif 2025 2026 pthread_mutex_init(&sbamtx, NULL); 2027 pthread_cond_init(&sbacv, NULL); 2028 2029 DPRINTF(("rump_sp: server mainloop\n")); 2030 2031 for (;;) { 2032 int discoed; 2033 2034 /* g/c hangarounds (eventually) */ 2035 discoed = getdisco(); 2036 while (discoed--) { 2037 nfds--; 2038 idx = maxidx; 2039 while (idx) { 2040 if (pfdlist[idx].fd != -1) { 2041 maxidx = idx; 2042 break; 2043 } 2044 idx--; 2045 } 2046 DPRINTF(("rump_sp: set maxidx to [%u]\n", 2047 maxidx)); 2048 } 2049 2050 DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1)); 2051 seen = 0; 2052 rv = poll(pfdlist, maxidx+1, INFTIM); 2053 assert(maxidx+1 <= MAXCLI); 2054 assert(rv != 0); 2055 if (rv == -1) { 2056 if (errno == EINTR) 2057 continue; 2058 fprintf(stderr, "rump_spserver: poll returned %d\n", 2059 errno); 2060 break; 2061 } 2062 2063 for (idx = 0; seen < rv && idx < MAXCLI; idx++) { 2064 if ((pfdlist[idx].revents & POLLIN) == 0) 2065 continue; 2066 2067 seen++; 2068 DPRINTF(("rump_sp: activity at [%u] %d/%d\n", 2069 idx, seen, rv)); 2070 if (idx > 0) { 2071 spc = &spclist[idx]; 2072 DPRINTF(("rump_sp: mainloop read [%u]\n", idx)); 2073 switch (readframe(spc)) { 2074 case 0: 2075 break; 2076 case -1: 2077 serv_handledisco(idx); 2078 break; 2079 default: 2080 switch (spc->spc_hdr.rsp_class) { 2081 case RUMPSP_RESP: 2082 kickwaiter(spc); 2083 break; 2084 case RUMPSP_REQ: 2085 handlereq(spc); 2086 break; 2087 default: 2088 send_error_resp(spc, 2089 spc->spc_hdr.rsp_reqno, 2090 RUMPSP_ERR_MALFORMED_REQUEST); 2091 spcfreebuf(spc); 2092 break; 2093 } 2094 break; 2095 } 2096 2097 } else { 2098 DPRINTF(("rump_sp: mainloop new connection\n")); 2099 2100 if (__predict_false(spfini)) { 2101 close(spclist[0].spc_fd); 2102 serv_shutdown(); 2103 goto out; 2104 } 2105 2106 idx = serv_handleconn(pfdlist[0].fd, 2107 sarg->sps_connhook, nfds == MAXCLI); 2108 if (idx) 2109 nfds++; 2110 if (idx > maxidx) 2111 maxidx = idx; 2112 DPRINTF(("rump_sp: maxid now %d\n", maxidx)); 2113 } 2114 } 2115 } 2116 2117 out: 2118 return NULL; 2119} 2120 2121static unsigned cleanupidx; 2122static struct sockaddr *cleanupsa; 2123int 2124rumpuser_sp_init(const char *url, 2125 const char *ostype, const char *osrelease, const char *machine) 2126{ 2127 pthread_t pt; 2128 struct spservarg *sarg; 2129 struct sockaddr *sap; 2130 char *p; 2131 unsigned idx = 0; /* XXXgcc */ 2132 int error, s; 2133 2134 p = strdup(url); 2135 if (p == NULL) { 2136 error = ENOMEM; 2137 goto out; 2138 } 2139 error = parseurl(p, &sap, &idx, 1); 2140 free(p); 2141 if (error) 2142 goto out; 2143 2144 snprintf(banner, sizeof(banner), "RUMPSP-%d.%d-%s-%s/%s\n", 2145 PROTOMAJOR, PROTOMINOR, ostype, osrelease, machine); 2146 2147 s = socket(parsetab[idx].domain, SOCK_STREAM, 0); 2148 if (s == -1) { 2149 error = errno; 2150 goto out; 2151 } 2152 2153 sarg = malloc(sizeof(*sarg)); 2154 if (sarg == NULL) { 2155 close(s); 2156 error = ENOMEM; 2157 goto out; 2158 } 2159 2160 sarg->sps_sock = s; 2161 sarg->sps_connhook = parsetab[idx].connhook; 2162 2163 cleanupidx = idx; 2164 cleanupsa = sap; 2165 2166 /* sloppy error recovery */ 2167 2168 /*LINTED*/ 2169 if (bind(s, sap, parsetab[idx].slen) == -1) { 2170 error = errno; 2171 fprintf(stderr, "rump_sp: server bind failed\n"); 2172 goto out; 2173 } 2174 if (listen(s, MAXCLI) == -1) { 2175 error = errno; 2176 fprintf(stderr, "rump_sp: server listen failed\n"); 2177 goto out; 2178 } 2179 2180 if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) { 2181 fprintf(stderr, "rump_sp: cannot create wrkr thread\n"); 2182 goto out; 2183 } 2184 pthread_detach(pt); 2185 2186 out: 2187 ET(error); 2188} 2189 2190void 2191rumpuser_sp_fini(void *arg) 2192{ 2193 struct spclient *spc = arg; 2194 register_t retval[2] = {0, 0}; 2195 int nlocks; 2196 2197 /* 2198 * ok, so, um, our lwp will change in this routine. 2199 * that's, ahm, um, eh, "interesting". However, it 2200 * shouldn't matter too much, since we're shutting down 2201 * anyway, and this call is most likely following by 2202 * rumpuser_exit() 2203 * 2204 * (strictly speaking, one could shut down the sysproxy 2205 * service without halting ... but you know what, we'll 2206 * call it a feature) 2207 */ 2208 2209 rumpkern_unsched(&nlocks, NULL); 2210 lwproc_newlwp(1); 2211 2212 if (spclist[0].spc_fd) { 2213 parsetab[cleanupidx].cleanup(cleanupsa); 2214 } 2215 2216 /* 2217 * stuff response into the socket, since the rump kernel container 2218 * is just about to exit 2219 */ 2220 if (spc && spc->spc_syscallreq) 2221 send_syscall_resp(spc, spc->spc_syscallreq, 0, retval); 2222 2223 if (spclist[0].spc_fd) { 2224 shutdown(spclist[0].spc_fd, SHUT_RDWR); 2225 spfini = 1; 2226 } 2227 2228} 2229