1 1.77 christos /* $NetBSD: rumpuser_sp.c,v 1.77 2020/05/06 12:44:36 christos Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.29 pooka * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Redistribution and use in source and binary forms, with or without 7 1.1 pooka * modification, are permitted provided that the following conditions 8 1.1 pooka * are met: 9 1.1 pooka * 1. Redistributions of source code must retain the above copyright 10 1.1 pooka * notice, this list of conditions and the following disclaimer. 11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 pooka * notice, this list of conditions and the following disclaimer in the 13 1.1 pooka * documentation and/or other materials provided with the distribution. 14 1.1 pooka * 15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 pooka * SUCH DAMAGE. 26 1.1 pooka */ 27 1.1 pooka 28 1.1 pooka /* 29 1.1 pooka * Sysproxy routines. This provides system RPC support over host sockets. 30 1.1 pooka * The most notable limitation is that the client and server must share 31 1.1 pooka * the same ABI. This does not mean that they have to be the same 32 1.1 pooka * machine or that they need to run the same version of the host OS, 33 1.1 pooka * just that they must agree on the data structures. This even *might* 34 1.1 pooka * work correctly from one hardware architecture to another. 35 1.1 pooka */ 36 1.1 pooka 37 1.47 pooka #include "rumpuser_port.h" 38 1.47 pooka 39 1.47 pooka #if !defined(lint) 40 1.77 christos __RCSID("$NetBSD: rumpuser_sp.c,v 1.77 2020/05/06 12:44:36 christos Exp $"); 41 1.47 pooka #endif /* !lint */ 42 1.1 pooka 43 1.1 pooka #include <sys/types.h> 44 1.1 pooka #include <sys/mman.h> 45 1.1 pooka #include <sys/socket.h> 46 1.1 pooka 47 1.1 pooka #include <arpa/inet.h> 48 1.1 pooka #include <netinet/in.h> 49 1.1 pooka #include <netinet/tcp.h> 50 1.1 pooka 51 1.1 pooka #include <assert.h> 52 1.1 pooka #include <errno.h> 53 1.1 pooka #include <fcntl.h> 54 1.1 pooka #include <poll.h> 55 1.1 pooka #include <pthread.h> 56 1.1 pooka #include <stdarg.h> 57 1.1 pooka #include <stdio.h> 58 1.1 pooka #include <stdlib.h> 59 1.1 pooka #include <string.h> 60 1.1 pooka #include <unistd.h> 61 1.1 pooka 62 1.28 pooka #include <rump/rump.h> /* XXX: for rfork flags */ 63 1.1 pooka #include <rump/rumpuser.h> 64 1.47 pooka 65 1.13 pooka #include "rumpuser_int.h" 66 1.1 pooka 67 1.5 pooka #include "sp_common.c" 68 1.1 pooka 69 1.20 pooka #ifndef MAXCLI 70 1.18 pooka #define MAXCLI 256 71 1.20 pooka #endif 72 1.20 pooka #ifndef MAXWORKER 73 1.20 pooka #define MAXWORKER 128 74 1.20 pooka #endif 75 1.20 pooka #ifndef IDLEWORKER 76 1.20 pooka #define IDLEWORKER 16 77 1.20 pooka #endif 78 1.20 pooka int rumpsp_maxworker = MAXWORKER; 79 1.20 pooka int rumpsp_idleworker = IDLEWORKER; 80 1.1 pooka 81 1.1 pooka static struct pollfd pfdlist[MAXCLI]; 82 1.1 pooka static struct spclient spclist[MAXCLI]; 83 1.11 pooka static unsigned int disco; 84 1.24 pooka static volatile int spfini; 85 1.1 pooka 86 1.26 pooka static char banner[MAXBANNER]; 87 1.26 pooka 88 1.26 pooka #define PROTOMAJOR 0 89 1.48 pooka #define PROTOMINOR 4 90 1.29 pooka 91 1.47 pooka 92 1.70 pooka /* either no atomic ops, or we haven't figured out how to use them */ 93 1.70 pooka #if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__OpenBSD__) || defined(__GNU__) || defined(__GLIBC__) 94 1.47 pooka static pthread_mutex_t discomtx = PTHREAD_MUTEX_INITIALIZER; 95 1.47 pooka 96 1.47 pooka static void 97 1.47 pooka signaldisco(void) 98 1.47 pooka { 99 1.47 pooka 100 1.47 pooka pthread_mutex_lock(&discomtx); 101 1.47 pooka disco++; 102 1.47 pooka pthread_mutex_unlock(&discomtx); 103 1.47 pooka } 104 1.47 pooka 105 1.47 pooka static unsigned int 106 1.47 pooka getdisco(void) 107 1.47 pooka { 108 1.47 pooka unsigned int discocnt; 109 1.47 pooka 110 1.47 pooka pthread_mutex_lock(&discomtx); 111 1.47 pooka discocnt = disco; 112 1.47 pooka disco = 0; 113 1.47 pooka pthread_mutex_unlock(&discomtx); 114 1.47 pooka 115 1.47 pooka return discocnt; 116 1.47 pooka } 117 1.47 pooka 118 1.50 pooka #elif defined(__FreeBSD__) || defined(__DragonFly__) 119 1.49 pooka 120 1.49 pooka #include <machine/atomic.h> 121 1.49 pooka #define signaldisco() atomic_add_int(&disco, 1) 122 1.49 pooka #define getdisco() atomic_readandclear_int(&disco) 123 1.49 pooka 124 1.47 pooka #else /* NetBSD */ 125 1.47 pooka 126 1.47 pooka #include <sys/atomic.h> 127 1.47 pooka #define signaldisco() atomic_inc_uint(&disco) 128 1.47 pooka #define getdisco() atomic_swap_uint(&disco, 0) 129 1.47 pooka 130 1.47 pooka #endif 131 1.47 pooka 132 1.47 pooka 133 1.29 pooka struct prefork { 134 1.29 pooka uint32_t pf_auth[AUTHLEN]; 135 1.29 pooka struct lwp *pf_lwp; 136 1.29 pooka 137 1.29 pooka LIST_ENTRY(prefork) pf_entries; /* global list */ 138 1.29 pooka LIST_ENTRY(prefork) pf_spcentries; /* linked from forking spc */ 139 1.29 pooka }; 140 1.29 pooka static LIST_HEAD(, prefork) preforks = LIST_HEAD_INITIALIZER(preforks); 141 1.29 pooka static pthread_mutex_t pfmtx; 142 1.26 pooka 143 1.3 pooka /* 144 1.31 pooka * This version is for the server. It's optimized for multiple threads 145 1.33 pooka * and is *NOT* reentrant wrt to signals. 146 1.31 pooka */ 147 1.31 pooka static int 148 1.31 pooka waitresp(struct spclient *spc, struct respwait *rw) 149 1.31 pooka { 150 1.34 pooka int spcstate; 151 1.31 pooka int rv = 0; 152 1.31 pooka 153 1.34 pooka pthread_mutex_lock(&spc->spc_mtx); 154 1.31 pooka sendunlockl(spc); 155 1.33 pooka while (!rw->rw_done && spc->spc_state != SPCSTATE_DYING) { 156 1.33 pooka pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx); 157 1.31 pooka } 158 1.31 pooka TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries); 159 1.34 pooka spcstate = spc->spc_state; 160 1.31 pooka pthread_mutex_unlock(&spc->spc_mtx); 161 1.31 pooka 162 1.31 pooka pthread_cond_destroy(&rw->rw_cv); 163 1.31 pooka 164 1.31 pooka if (rv) 165 1.31 pooka return rv; 166 1.34 pooka if (spcstate == SPCSTATE_DYING) 167 1.31 pooka return ENOTCONN; 168 1.31 pooka return rw->rw_error; 169 1.31 pooka } 170 1.31 pooka 171 1.31 pooka /* 172 1.3 pooka * Manual wrappers, since librump does not have access to the 173 1.3 pooka * user namespace wrapped interfaces. 174 1.3 pooka */ 175 1.3 pooka 176 1.3 pooka static void 177 1.3 pooka lwproc_switch(struct lwp *l) 178 1.3 pooka { 179 1.3 pooka 180 1.56 pooka rumpuser__hyp.hyp_schedule(); 181 1.56 pooka rumpuser__hyp.hyp_lwproc_switch(l); 182 1.56 pooka rumpuser__hyp.hyp_unschedule(); 183 1.3 pooka } 184 1.3 pooka 185 1.3 pooka static void 186 1.3 pooka lwproc_release(void) 187 1.3 pooka { 188 1.3 pooka 189 1.56 pooka rumpuser__hyp.hyp_schedule(); 190 1.56 pooka rumpuser__hyp.hyp_lwproc_release(); 191 1.56 pooka rumpuser__hyp.hyp_unschedule(); 192 1.3 pooka } 193 1.3 pooka 194 1.3 pooka static int 195 1.38 pooka lwproc_rfork(struct spclient *spc, int flags, const char *comm) 196 1.3 pooka { 197 1.3 pooka int rv; 198 1.3 pooka 199 1.56 pooka rumpuser__hyp.hyp_schedule(); 200 1.56 pooka rv = rumpuser__hyp.hyp_lwproc_rfork(spc, flags, comm); 201 1.56 pooka rumpuser__hyp.hyp_unschedule(); 202 1.3 pooka 203 1.3 pooka return rv; 204 1.3 pooka } 205 1.3 pooka 206 1.8 pooka static int 207 1.8 pooka lwproc_newlwp(pid_t pid) 208 1.8 pooka { 209 1.8 pooka int rv; 210 1.8 pooka 211 1.56 pooka rumpuser__hyp.hyp_schedule(); 212 1.56 pooka rv = rumpuser__hyp.hyp_lwproc_newlwp(pid); 213 1.56 pooka rumpuser__hyp.hyp_unschedule(); 214 1.8 pooka 215 1.8 pooka return rv; 216 1.8 pooka } 217 1.8 pooka 218 1.3 pooka static struct lwp * 219 1.3 pooka lwproc_curlwp(void) 220 1.3 pooka { 221 1.3 pooka struct lwp *l; 222 1.3 pooka 223 1.56 pooka rumpuser__hyp.hyp_schedule(); 224 1.56 pooka l = rumpuser__hyp.hyp_lwproc_curlwp(); 225 1.56 pooka rumpuser__hyp.hyp_unschedule(); 226 1.3 pooka 227 1.3 pooka return l; 228 1.3 pooka } 229 1.3 pooka 230 1.8 pooka static pid_t 231 1.8 pooka lwproc_getpid(void) 232 1.8 pooka { 233 1.8 pooka pid_t p; 234 1.8 pooka 235 1.56 pooka rumpuser__hyp.hyp_schedule(); 236 1.56 pooka p = rumpuser__hyp.hyp_getpid(); 237 1.56 pooka rumpuser__hyp.hyp_unschedule(); 238 1.8 pooka 239 1.8 pooka return p; 240 1.8 pooka } 241 1.44 pooka 242 1.41 pooka static void 243 1.41 pooka lwproc_execnotify(const char *comm) 244 1.41 pooka { 245 1.41 pooka 246 1.56 pooka rumpuser__hyp.hyp_schedule(); 247 1.56 pooka rumpuser__hyp.hyp_execnotify(comm); 248 1.56 pooka rumpuser__hyp.hyp_unschedule(); 249 1.41 pooka } 250 1.8 pooka 251 1.35 pooka static void 252 1.44 pooka lwproc_lwpexit(void) 253 1.35 pooka { 254 1.35 pooka 255 1.56 pooka rumpuser__hyp.hyp_schedule(); 256 1.56 pooka rumpuser__hyp.hyp_lwpexit(); 257 1.56 pooka rumpuser__hyp.hyp_unschedule(); 258 1.35 pooka } 259 1.35 pooka 260 1.3 pooka static int 261 1.53 pooka rumpsyscall(int sysnum, void *data, register_t *regrv) 262 1.3 pooka { 263 1.53 pooka long retval[2] = {0, 0}; 264 1.3 pooka int rv; 265 1.3 pooka 266 1.56 pooka rumpuser__hyp.hyp_schedule(); 267 1.56 pooka rv = rumpuser__hyp.hyp_syscall(sysnum, data, retval); 268 1.56 pooka rumpuser__hyp.hyp_unschedule(); 269 1.3 pooka 270 1.53 pooka regrv[0] = retval[0]; 271 1.53 pooka regrv[1] = retval[1]; 272 1.3 pooka return rv; 273 1.3 pooka } 274 1.1 pooka 275 1.7 pooka static uint64_t 276 1.7 pooka nextreq(struct spclient *spc) 277 1.7 pooka { 278 1.7 pooka uint64_t nw; 279 1.7 pooka 280 1.7 pooka pthread_mutex_lock(&spc->spc_mtx); 281 1.7 pooka nw = spc->spc_nextreq++; 282 1.7 pooka pthread_mutex_unlock(&spc->spc_mtx); 283 1.7 pooka 284 1.7 pooka return nw; 285 1.7 pooka } 286 1.7 pooka 287 1.45 pooka /* 288 1.45 pooka * XXX: we send responses with "blocking" I/O. This is not 289 1.45 pooka * ok for the main thread. XXXFIXME 290 1.45 pooka */ 291 1.45 pooka 292 1.21 pooka static void 293 1.48 pooka send_error_resp(struct spclient *spc, uint64_t reqno, enum rumpsp_err error) 294 1.21 pooka { 295 1.21 pooka struct rsp_hdr rhdr; 296 1.45 pooka struct iovec iov[1]; 297 1.21 pooka 298 1.21 pooka rhdr.rsp_len = sizeof(rhdr); 299 1.21 pooka rhdr.rsp_reqno = reqno; 300 1.21 pooka rhdr.rsp_class = RUMPSP_ERROR; 301 1.21 pooka rhdr.rsp_type = 0; 302 1.21 pooka rhdr.rsp_error = error; 303 1.21 pooka 304 1.45 pooka IOVPUT(iov[0], rhdr); 305 1.45 pooka 306 1.21 pooka sendlock(spc); 307 1.45 pooka (void)SENDIOV(spc, iov); 308 1.21 pooka sendunlock(spc); 309 1.21 pooka } 310 1.21 pooka 311 1.1 pooka static int 312 1.27 pooka send_handshake_resp(struct spclient *spc, uint64_t reqno, int error) 313 1.27 pooka { 314 1.27 pooka struct rsp_hdr rhdr; 315 1.45 pooka struct iovec iov[2]; 316 1.27 pooka int rv; 317 1.27 pooka 318 1.27 pooka rhdr.rsp_len = sizeof(rhdr) + sizeof(error); 319 1.27 pooka rhdr.rsp_reqno = reqno; 320 1.27 pooka rhdr.rsp_class = RUMPSP_RESP; 321 1.27 pooka rhdr.rsp_type = RUMPSP_HANDSHAKE; 322 1.27 pooka rhdr.rsp_error = 0; 323 1.27 pooka 324 1.45 pooka IOVPUT(iov[0], rhdr); 325 1.45 pooka IOVPUT(iov[1], error); 326 1.45 pooka 327 1.27 pooka sendlock(spc); 328 1.45 pooka rv = SENDIOV(spc, iov); 329 1.27 pooka sendunlock(spc); 330 1.27 pooka 331 1.27 pooka return rv; 332 1.27 pooka } 333 1.27 pooka 334 1.27 pooka static int 335 1.1 pooka send_syscall_resp(struct spclient *spc, uint64_t reqno, int error, 336 1.7 pooka register_t *retval) 337 1.1 pooka { 338 1.1 pooka struct rsp_hdr rhdr; 339 1.1 pooka struct rsp_sysresp sysresp; 340 1.45 pooka struct iovec iov[2]; 341 1.7 pooka int rv; 342 1.1 pooka 343 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp); 344 1.1 pooka rhdr.rsp_reqno = reqno; 345 1.7 pooka rhdr.rsp_class = RUMPSP_RESP; 346 1.7 pooka rhdr.rsp_type = RUMPSP_SYSCALL; 347 1.1 pooka rhdr.rsp_sysnum = 0; 348 1.1 pooka 349 1.1 pooka sysresp.rsys_error = error; 350 1.7 pooka memcpy(sysresp.rsys_retval, retval, sizeof(sysresp.rsys_retval)); 351 1.1 pooka 352 1.45 pooka IOVPUT(iov[0], rhdr); 353 1.45 pooka IOVPUT(iov[1], sysresp); 354 1.45 pooka 355 1.7 pooka sendlock(spc); 356 1.45 pooka rv = SENDIOV(spc, iov); 357 1.7 pooka sendunlock(spc); 358 1.1 pooka 359 1.7 pooka return rv; 360 1.1 pooka } 361 1.1 pooka 362 1.1 pooka static int 363 1.29 pooka send_prefork_resp(struct spclient *spc, uint64_t reqno, uint32_t *auth) 364 1.29 pooka { 365 1.29 pooka struct rsp_hdr rhdr; 366 1.45 pooka struct iovec iov[2]; 367 1.29 pooka int rv; 368 1.29 pooka 369 1.29 pooka rhdr.rsp_len = sizeof(rhdr) + AUTHLEN*sizeof(*auth); 370 1.29 pooka rhdr.rsp_reqno = reqno; 371 1.29 pooka rhdr.rsp_class = RUMPSP_RESP; 372 1.29 pooka rhdr.rsp_type = RUMPSP_PREFORK; 373 1.29 pooka rhdr.rsp_sysnum = 0; 374 1.29 pooka 375 1.45 pooka IOVPUT(iov[0], rhdr); 376 1.45 pooka IOVPUT_WITHSIZE(iov[1], auth, AUTHLEN*sizeof(*auth)); 377 1.45 pooka 378 1.29 pooka sendlock(spc); 379 1.45 pooka rv = SENDIOV(spc, iov); 380 1.29 pooka sendunlock(spc); 381 1.29 pooka 382 1.29 pooka return rv; 383 1.29 pooka } 384 1.29 pooka 385 1.29 pooka static int 386 1.15 pooka copyin_req(struct spclient *spc, const void *remaddr, size_t *dlen, 387 1.15 pooka int wantstr, void **resp) 388 1.1 pooka { 389 1.1 pooka struct rsp_hdr rhdr; 390 1.1 pooka struct rsp_copydata copydata; 391 1.7 pooka struct respwait rw; 392 1.45 pooka struct iovec iov[2]; 393 1.7 pooka int rv; 394 1.7 pooka 395 1.15 pooka DPRINTF(("copyin_req: %zu bytes from %p\n", *dlen, remaddr)); 396 1.1 pooka 397 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata); 398 1.7 pooka rhdr.rsp_class = RUMPSP_REQ; 399 1.15 pooka if (wantstr) 400 1.15 pooka rhdr.rsp_type = RUMPSP_COPYINSTR; 401 1.15 pooka else 402 1.15 pooka rhdr.rsp_type = RUMPSP_COPYIN; 403 1.1 pooka rhdr.rsp_sysnum = 0; 404 1.1 pooka 405 1.1 pooka copydata.rcp_addr = __UNCONST(remaddr); 406 1.15 pooka copydata.rcp_len = *dlen; 407 1.1 pooka 408 1.45 pooka IOVPUT(iov[0], rhdr); 409 1.45 pooka IOVPUT(iov[1], copydata); 410 1.45 pooka 411 1.7 pooka putwait(spc, &rw, &rhdr); 412 1.45 pooka rv = SENDIOV(spc, iov); 413 1.13 pooka if (rv) { 414 1.13 pooka unputwait(spc, &rw); 415 1.13 pooka return rv; 416 1.13 pooka } 417 1.7 pooka 418 1.7 pooka rv = waitresp(spc, &rw); 419 1.7 pooka 420 1.7 pooka DPRINTF(("copyin: response %d\n", rv)); 421 1.7 pooka 422 1.7 pooka *resp = rw.rw_data; 423 1.15 pooka if (wantstr) 424 1.15 pooka *dlen = rw.rw_dlen; 425 1.15 pooka 426 1.7 pooka return rv; 427 1.1 pooka 428 1.1 pooka } 429 1.1 pooka 430 1.1 pooka static int 431 1.1 pooka send_copyout_req(struct spclient *spc, const void *remaddr, 432 1.1 pooka const void *data, size_t dlen) 433 1.1 pooka { 434 1.1 pooka struct rsp_hdr rhdr; 435 1.1 pooka struct rsp_copydata copydata; 436 1.45 pooka struct iovec iov[3]; 437 1.7 pooka int rv; 438 1.7 pooka 439 1.7 pooka DPRINTF(("copyout_req (async): %zu bytes to %p\n", dlen, remaddr)); 440 1.1 pooka 441 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen; 442 1.7 pooka rhdr.rsp_reqno = nextreq(spc); 443 1.7 pooka rhdr.rsp_class = RUMPSP_REQ; 444 1.7 pooka rhdr.rsp_type = RUMPSP_COPYOUT; 445 1.1 pooka rhdr.rsp_sysnum = 0; 446 1.1 pooka 447 1.1 pooka copydata.rcp_addr = __UNCONST(remaddr); 448 1.1 pooka copydata.rcp_len = dlen; 449 1.1 pooka 450 1.45 pooka IOVPUT(iov[0], rhdr); 451 1.45 pooka IOVPUT(iov[1], copydata); 452 1.45 pooka IOVPUT_WITHSIZE(iov[2], __UNCONST(data), dlen); 453 1.45 pooka 454 1.7 pooka sendlock(spc); 455 1.45 pooka rv = SENDIOV(spc, iov); 456 1.7 pooka sendunlock(spc); 457 1.1 pooka 458 1.7 pooka return rv; 459 1.1 pooka } 460 1.1 pooka 461 1.1 pooka static int 462 1.7 pooka anonmmap_req(struct spclient *spc, size_t howmuch, void **resp) 463 1.1 pooka { 464 1.1 pooka struct rsp_hdr rhdr; 465 1.7 pooka struct respwait rw; 466 1.45 pooka struct iovec iov[2]; 467 1.7 pooka int rv; 468 1.7 pooka 469 1.7 pooka DPRINTF(("anonmmap_req: %zu bytes\n", howmuch)); 470 1.1 pooka 471 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch); 472 1.7 pooka rhdr.rsp_class = RUMPSP_REQ; 473 1.7 pooka rhdr.rsp_type = RUMPSP_ANONMMAP; 474 1.1 pooka rhdr.rsp_sysnum = 0; 475 1.1 pooka 476 1.45 pooka IOVPUT(iov[0], rhdr); 477 1.45 pooka IOVPUT(iov[1], howmuch); 478 1.45 pooka 479 1.7 pooka putwait(spc, &rw, &rhdr); 480 1.45 pooka rv = SENDIOV(spc, iov); 481 1.13 pooka if (rv) { 482 1.13 pooka unputwait(spc, &rw); 483 1.13 pooka return rv; 484 1.13 pooka } 485 1.1 pooka 486 1.7 pooka rv = waitresp(spc, &rw); 487 1.13 pooka 488 1.7 pooka *resp = rw.rw_data; 489 1.7 pooka 490 1.7 pooka DPRINTF(("anonmmap: mapped at %p\n", **(void ***)resp)); 491 1.7 pooka 492 1.7 pooka return rv; 493 1.1 pooka } 494 1.1 pooka 495 1.36 pooka static int 496 1.36 pooka send_raise_req(struct spclient *spc, int signo) 497 1.36 pooka { 498 1.36 pooka struct rsp_hdr rhdr; 499 1.45 pooka struct iovec iov[1]; 500 1.36 pooka int rv; 501 1.36 pooka 502 1.36 pooka rhdr.rsp_len = sizeof(rhdr); 503 1.36 pooka rhdr.rsp_class = RUMPSP_REQ; 504 1.36 pooka rhdr.rsp_type = RUMPSP_RAISE; 505 1.36 pooka rhdr.rsp_signo = signo; 506 1.36 pooka 507 1.45 pooka IOVPUT(iov[0], rhdr); 508 1.45 pooka 509 1.36 pooka sendlock(spc); 510 1.45 pooka rv = SENDIOV(spc, iov); 511 1.36 pooka sendunlock(spc); 512 1.36 pooka 513 1.36 pooka return rv; 514 1.36 pooka } 515 1.36 pooka 516 1.1 pooka static void 517 1.11 pooka spcref(struct spclient *spc) 518 1.11 pooka { 519 1.11 pooka 520 1.11 pooka pthread_mutex_lock(&spc->spc_mtx); 521 1.11 pooka spc->spc_refcnt++; 522 1.11 pooka pthread_mutex_unlock(&spc->spc_mtx); 523 1.11 pooka } 524 1.11 pooka 525 1.11 pooka static void 526 1.11 pooka spcrelease(struct spclient *spc) 527 1.11 pooka { 528 1.11 pooka int ref; 529 1.11 pooka 530 1.11 pooka pthread_mutex_lock(&spc->spc_mtx); 531 1.11 pooka ref = --spc->spc_refcnt; 532 1.44 pooka if (__predict_false(spc->spc_inexec && ref <= 2)) 533 1.44 pooka pthread_cond_broadcast(&spc->spc_cv); 534 1.11 pooka pthread_mutex_unlock(&spc->spc_mtx); 535 1.11 pooka 536 1.11 pooka if (ref > 0) 537 1.11 pooka return; 538 1.11 pooka 539 1.29 pooka DPRINTF(("rump_sp: spcrelease: spc %p fd %d\n", spc, spc->spc_fd)); 540 1.12 pooka 541 1.13 pooka _DIAGASSERT(TAILQ_EMPTY(&spc->spc_respwait)); 542 1.11 pooka _DIAGASSERT(spc->spc_buf == NULL); 543 1.11 pooka 544 1.29 pooka if (spc->spc_mainlwp) { 545 1.29 pooka lwproc_switch(spc->spc_mainlwp); 546 1.29 pooka lwproc_release(); 547 1.29 pooka } 548 1.11 pooka spc->spc_mainlwp = NULL; 549 1.11 pooka 550 1.11 pooka close(spc->spc_fd); 551 1.11 pooka spc->spc_fd = -1; 552 1.27 pooka spc->spc_state = SPCSTATE_NEW; 553 1.11 pooka 554 1.47 pooka signaldisco(); 555 1.11 pooka } 556 1.11 pooka 557 1.11 pooka static void 558 1.2 pooka serv_handledisco(unsigned int idx) 559 1.1 pooka { 560 1.1 pooka struct spclient *spc = &spclist[idx]; 561 1.44 pooka int dolwpexit; 562 1.1 pooka 563 1.1 pooka DPRINTF(("rump_sp: disconnecting [%u]\n", idx)); 564 1.1 pooka 565 1.12 pooka pfdlist[idx].fd = -1; 566 1.12 pooka pfdlist[idx].revents = 0; 567 1.12 pooka pthread_mutex_lock(&spc->spc_mtx); 568 1.27 pooka spc->spc_state = SPCSTATE_DYING; 569 1.12 pooka kickall(spc); 570 1.30 pooka sendunlockl(spc); 571 1.44 pooka /* exec uses mainlwp in another thread, but also nuked all lwps */ 572 1.44 pooka dolwpexit = !spc->spc_inexec; 573 1.12 pooka pthread_mutex_unlock(&spc->spc_mtx); 574 1.17 pooka 575 1.44 pooka if (dolwpexit && spc->spc_mainlwp) { 576 1.35 pooka lwproc_switch(spc->spc_mainlwp); 577 1.44 pooka lwproc_lwpexit(); 578 1.35 pooka lwproc_switch(NULL); 579 1.35 pooka } 580 1.35 pooka 581 1.17 pooka /* 582 1.17 pooka * Nobody's going to attempt to send/receive anymore, 583 1.17 pooka * so reinit info relevant to that. 584 1.17 pooka */ 585 1.22 pooka /*LINTED:pointer casts may be ok*/ 586 1.17 pooka memset((char *)spc + SPC_ZEROFF, 0, sizeof(*spc) - SPC_ZEROFF); 587 1.17 pooka 588 1.11 pooka spcrelease(spc); 589 1.1 pooka } 590 1.1 pooka 591 1.24 pooka static void 592 1.24 pooka serv_shutdown(void) 593 1.24 pooka { 594 1.24 pooka struct spclient *spc; 595 1.24 pooka unsigned int i; 596 1.24 pooka 597 1.24 pooka for (i = 1; i < MAXCLI; i++) { 598 1.24 pooka spc = &spclist[i]; 599 1.24 pooka if (spc->spc_fd == -1) 600 1.24 pooka continue; 601 1.24 pooka 602 1.24 pooka shutdown(spc->spc_fd, SHUT_RDWR); 603 1.24 pooka serv_handledisco(i); 604 1.24 pooka 605 1.24 pooka spcrelease(spc); 606 1.24 pooka } 607 1.24 pooka } 608 1.24 pooka 609 1.11 pooka static unsigned 610 1.11 pooka serv_handleconn(int fd, connecthook_fn connhook, int busy) 611 1.1 pooka { 612 1.1 pooka struct sockaddr_storage ss; 613 1.1 pooka socklen_t sl = sizeof(ss); 614 1.11 pooka int newfd, flags; 615 1.1 pooka unsigned i; 616 1.1 pooka 617 1.1 pooka /*LINTED: cast ok */ 618 1.1 pooka newfd = accept(fd, (struct sockaddr *)&ss, &sl); 619 1.1 pooka if (newfd == -1) 620 1.11 pooka return 0; 621 1.1 pooka 622 1.11 pooka if (busy) { 623 1.1 pooka close(newfd); /* EBUSY */ 624 1.11 pooka return 0; 625 1.1 pooka } 626 1.1 pooka 627 1.1 pooka flags = fcntl(newfd, F_GETFL, 0); 628 1.1 pooka if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) { 629 1.1 pooka close(newfd); 630 1.11 pooka return 0; 631 1.1 pooka } 632 1.1 pooka 633 1.11 pooka if (connhook(newfd) != 0) { 634 1.1 pooka close(newfd); 635 1.11 pooka return 0; 636 1.1 pooka } 637 1.1 pooka 638 1.26 pooka /* write out a banner for the client */ 639 1.34 pooka if (send(newfd, banner, strlen(banner), MSG_NOSIGNAL) 640 1.34 pooka != (ssize_t)strlen(banner)) { 641 1.26 pooka close(newfd); 642 1.26 pooka return 0; 643 1.26 pooka } 644 1.26 pooka 645 1.1 pooka /* find empty slot the simple way */ 646 1.1 pooka for (i = 0; i < MAXCLI; i++) { 647 1.27 pooka if (pfdlist[i].fd == -1 && spclist[i].spc_state == SPCSTATE_NEW) 648 1.2 pooka break; 649 1.1 pooka } 650 1.1 pooka 651 1.59 pooka /* 652 1.59 pooka * Although not finding a slot is impossible (cf. how this routine 653 1.59 pooka * is called), the compiler can still think that i == MAXCLI 654 1.59 pooka * if this code is either compiled with NDEBUG or the platform 655 1.59 pooka * does not use __dead for assert(). Therefore, add an explicit 656 1.59 pooka * check to avoid an array-bounds error. 657 1.59 pooka */ 658 1.59 pooka /* assert(i < MAXCLI); */ 659 1.59 pooka if (i == MAXCLI) 660 1.59 pooka abort(); 661 1.1 pooka 662 1.1 pooka pfdlist[i].fd = newfd; 663 1.1 pooka spclist[i].spc_fd = newfd; 664 1.7 pooka spclist[i].spc_istatus = SPCSTATUS_BUSY; /* dedicated receiver */ 665 1.11 pooka spclist[i].spc_refcnt = 1; 666 1.7 pooka 667 1.7 pooka TAILQ_INIT(&spclist[i].spc_respwait); 668 1.1 pooka 669 1.29 pooka DPRINTF(("rump_sp: added new connection fd %d at idx %u\n", newfd, i)); 670 1.1 pooka 671 1.11 pooka return i; 672 1.1 pooka } 673 1.1 pooka 674 1.1 pooka static void 675 1.1 pooka serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data) 676 1.1 pooka { 677 1.7 pooka register_t retval[2] = {0, 0}; 678 1.1 pooka int rv, sysnum; 679 1.1 pooka 680 1.1 pooka sysnum = (int)rhdr->rsp_sysnum; 681 1.1 pooka DPRINTF(("rump_sp: handling syscall %d from client %d\n", 682 1.29 pooka sysnum, spc->spc_pid)); 683 1.1 pooka 684 1.44 pooka if (__predict_false((rv = lwproc_newlwp(spc->spc_pid)) != 0)) { 685 1.44 pooka retval[0] = -1; 686 1.44 pooka send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval); 687 1.44 pooka return; 688 1.44 pooka } 689 1.37 pooka spc->spc_syscallreq = rhdr->rsp_reqno; 690 1.3 pooka rv = rumpsyscall(sysnum, data, retval); 691 1.37 pooka spc->spc_syscallreq = 0; 692 1.16 pooka lwproc_release(); 693 1.1 pooka 694 1.72 martin DPRINTF(("rump_sp: got return value %d & %"PRIxREGISTER 695 1.72 martin "/%"PRIxREGISTER"\n", 696 1.72 martin rv, retval[0], retval[1])); 697 1.5 pooka 698 1.1 pooka send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval); 699 1.1 pooka } 700 1.1 pooka 701 1.44 pooka static void 702 1.77 christos serv_handleexec(struct spclient *spc, struct rsp_hdr *rhdr, const char *comm) 703 1.44 pooka { 704 1.44 pooka pthread_mutex_lock(&spc->spc_mtx); 705 1.44 pooka /* one for the connection and one for us */ 706 1.44 pooka while (spc->spc_refcnt > 2) 707 1.44 pooka pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx); 708 1.44 pooka pthread_mutex_unlock(&spc->spc_mtx); 709 1.44 pooka 710 1.44 pooka /* 711 1.44 pooka * ok, all the threads are dead (or one is still alive and 712 1.44 pooka * the connection is dead, in which case this doesn't matter 713 1.44 pooka * very much). proceed with exec. 714 1.44 pooka */ 715 1.44 pooka 716 1.44 pooka lwproc_switch(spc->spc_mainlwp); 717 1.44 pooka lwproc_execnotify(comm); 718 1.44 pooka lwproc_switch(NULL); 719 1.44 pooka 720 1.44 pooka pthread_mutex_lock(&spc->spc_mtx); 721 1.44 pooka spc->spc_inexec = 0; 722 1.44 pooka pthread_mutex_unlock(&spc->spc_mtx); 723 1.44 pooka send_handshake_resp(spc, rhdr->rsp_reqno, 0); 724 1.44 pooka } 725 1.44 pooka 726 1.44 pooka enum sbatype { SBA_SYSCALL, SBA_EXEC }; 727 1.44 pooka 728 1.44 pooka struct servbouncearg { 729 1.7 pooka struct spclient *sba_spc; 730 1.7 pooka struct rsp_hdr sba_hdr; 731 1.44 pooka enum sbatype sba_type; 732 1.7 pooka uint8_t *sba_data; 733 1.20 pooka 734 1.44 pooka TAILQ_ENTRY(servbouncearg) sba_entries; 735 1.7 pooka }; 736 1.20 pooka static pthread_mutex_t sbamtx; 737 1.20 pooka static pthread_cond_t sbacv; 738 1.40 pooka static int nworker, idleworker, nwork; 739 1.44 pooka static TAILQ_HEAD(, servbouncearg) wrklist = TAILQ_HEAD_INITIALIZER(wrklist); 740 1.20 pooka 741 1.20 pooka /*ARGSUSED*/ 742 1.7 pooka static void * 743 1.44 pooka serv_workbouncer(void *arg) 744 1.7 pooka { 745 1.44 pooka struct servbouncearg *sba; 746 1.20 pooka 747 1.20 pooka for (;;) { 748 1.20 pooka pthread_mutex_lock(&sbamtx); 749 1.43 pooka if (__predict_false(idleworker - nwork >= rumpsp_idleworker)) { 750 1.20 pooka nworker--; 751 1.20 pooka pthread_mutex_unlock(&sbamtx); 752 1.20 pooka break; 753 1.20 pooka } 754 1.40 pooka idleworker++; 755 1.44 pooka while (TAILQ_EMPTY(&wrklist)) { 756 1.40 pooka _DIAGASSERT(nwork == 0); 757 1.20 pooka pthread_cond_wait(&sbacv, &sbamtx); 758 1.40 pooka } 759 1.40 pooka idleworker--; 760 1.20 pooka 761 1.44 pooka sba = TAILQ_FIRST(&wrklist); 762 1.44 pooka TAILQ_REMOVE(&wrklist, sba, sba_entries); 763 1.40 pooka nwork--; 764 1.20 pooka pthread_mutex_unlock(&sbamtx); 765 1.20 pooka 766 1.44 pooka if (__predict_true(sba->sba_type == SBA_SYSCALL)) { 767 1.44 pooka serv_handlesyscall(sba->sba_spc, 768 1.44 pooka &sba->sba_hdr, sba->sba_data); 769 1.44 pooka } else { 770 1.44 pooka _DIAGASSERT(sba->sba_type == SBA_EXEC); 771 1.44 pooka serv_handleexec(sba->sba_spc, &sba->sba_hdr, 772 1.44 pooka (char *)sba->sba_data); 773 1.44 pooka } 774 1.20 pooka spcrelease(sba->sba_spc); 775 1.20 pooka free(sba->sba_data); 776 1.20 pooka free(sba); 777 1.20 pooka } 778 1.7 pooka 779 1.7 pooka return NULL; 780 1.7 pooka } 781 1.7 pooka 782 1.15 pooka static int 783 1.15 pooka sp_copyin(void *arg, const void *raddr, void *laddr, size_t *len, int wantstr) 784 1.1 pooka { 785 1.10 pooka struct spclient *spc = arg; 786 1.9 pooka void *rdata = NULL; /* XXXuninit */ 787 1.13 pooka int rv, nlocks; 788 1.13 pooka 789 1.56 pooka rumpkern_unsched(&nlocks, NULL); 790 1.1 pooka 791 1.15 pooka rv = copyin_req(spc, raddr, len, wantstr, &rdata); 792 1.12 pooka if (rv) 793 1.13 pooka goto out; 794 1.1 pooka 795 1.15 pooka memcpy(laddr, rdata, *len); 796 1.7 pooka free(rdata); 797 1.1 pooka 798 1.13 pooka out: 799 1.56 pooka rumpkern_sched(nlocks, NULL); 800 1.13 pooka if (rv) 801 1.57 pooka rv = EFAULT; 802 1.58 pooka ET(rv); 803 1.1 pooka } 804 1.1 pooka 805 1.1 pooka int 806 1.15 pooka rumpuser_sp_copyin(void *arg, const void *raddr, void *laddr, size_t len) 807 1.15 pooka { 808 1.58 pooka int rv; 809 1.15 pooka 810 1.58 pooka rv = sp_copyin(arg, raddr, laddr, &len, 0); 811 1.58 pooka ET(rv); 812 1.15 pooka } 813 1.15 pooka 814 1.15 pooka int 815 1.15 pooka rumpuser_sp_copyinstr(void *arg, const void *raddr, void *laddr, size_t *len) 816 1.15 pooka { 817 1.58 pooka int rv; 818 1.15 pooka 819 1.58 pooka rv = sp_copyin(arg, raddr, laddr, len, 1); 820 1.58 pooka ET(rv); 821 1.15 pooka } 822 1.15 pooka 823 1.15 pooka static int 824 1.15 pooka sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen) 825 1.1 pooka { 826 1.10 pooka struct spclient *spc = arg; 827 1.13 pooka int nlocks, rv; 828 1.13 pooka 829 1.56 pooka rumpkern_unsched(&nlocks, NULL); 830 1.15 pooka rv = send_copyout_req(spc, raddr, laddr, dlen); 831 1.56 pooka rumpkern_sched(nlocks, NULL); 832 1.1 pooka 833 1.13 pooka if (rv) 834 1.57 pooka rv = EFAULT; 835 1.58 pooka ET(rv); 836 1.1 pooka } 837 1.1 pooka 838 1.1 pooka int 839 1.15 pooka rumpuser_sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen) 840 1.15 pooka { 841 1.58 pooka int rv; 842 1.15 pooka 843 1.58 pooka rv = sp_copyout(arg, laddr, raddr, dlen); 844 1.58 pooka ET(rv); 845 1.15 pooka } 846 1.15 pooka 847 1.15 pooka int 848 1.15 pooka rumpuser_sp_copyoutstr(void *arg, const void *laddr, void *raddr, size_t *dlen) 849 1.15 pooka { 850 1.58 pooka int rv; 851 1.15 pooka 852 1.58 pooka rv = sp_copyout(arg, laddr, raddr, *dlen); 853 1.58 pooka ET(rv); 854 1.15 pooka } 855 1.15 pooka 856 1.15 pooka int 857 1.10 pooka rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr) 858 1.1 pooka { 859 1.10 pooka struct spclient *spc = arg; 860 1.68 justin void *resp, *rdata = NULL; /* XXXuninit */ 861 1.13 pooka int nlocks, rv; 862 1.13 pooka 863 1.56 pooka rumpkern_unsched(&nlocks, NULL); 864 1.1 pooka 865 1.7 pooka rv = anonmmap_req(spc, howmuch, &rdata); 866 1.13 pooka if (rv) { 867 1.13 pooka rv = EFAULT; 868 1.13 pooka goto out; 869 1.13 pooka } 870 1.1 pooka 871 1.7 pooka resp = *(void **)rdata; 872 1.7 pooka free(rdata); 873 1.1 pooka 874 1.7 pooka if (resp == NULL) { 875 1.13 pooka rv = ENOMEM; 876 1.1 pooka } 877 1.1 pooka 878 1.1 pooka *addr = resp; 879 1.13 pooka 880 1.13 pooka out: 881 1.56 pooka rumpkern_sched(nlocks, NULL); 882 1.58 pooka ET(rv); 883 1.1 pooka } 884 1.1 pooka 885 1.36 pooka int 886 1.36 pooka rumpuser_sp_raise(void *arg, int signo) 887 1.36 pooka { 888 1.36 pooka struct spclient *spc = arg; 889 1.36 pooka int rv, nlocks; 890 1.36 pooka 891 1.56 pooka rumpkern_unsched(&nlocks, NULL); 892 1.36 pooka rv = send_raise_req(spc, signo); 893 1.56 pooka rumpkern_sched(nlocks, NULL); 894 1.36 pooka 895 1.36 pooka return rv; 896 1.36 pooka } 897 1.36 pooka 898 1.44 pooka static pthread_attr_t pattr_detached; 899 1.44 pooka static void 900 1.44 pooka schedulework(struct spclient *spc, enum sbatype sba_type) 901 1.44 pooka { 902 1.44 pooka struct servbouncearg *sba; 903 1.44 pooka pthread_t pt; 904 1.44 pooka uint64_t reqno; 905 1.44 pooka int retries = 0; 906 1.44 pooka 907 1.44 pooka reqno = spc->spc_hdr.rsp_reqno; 908 1.44 pooka while ((sba = malloc(sizeof(*sba))) == NULL) { 909 1.75 kre if (nworker == 0 || retries++ > 10) { 910 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_TRYAGAIN); 911 1.44 pooka spcfreebuf(spc); 912 1.44 pooka return; 913 1.44 pooka } 914 1.44 pooka /* slim chance of more memory? */ 915 1.44 pooka usleep(10000); 916 1.44 pooka } 917 1.44 pooka 918 1.44 pooka sba->sba_spc = spc; 919 1.44 pooka sba->sba_type = sba_type; 920 1.44 pooka sba->sba_hdr = spc->spc_hdr; 921 1.44 pooka sba->sba_data = spc->spc_buf; 922 1.44 pooka spcresetbuf(spc); 923 1.44 pooka 924 1.44 pooka spcref(spc); 925 1.44 pooka 926 1.44 pooka pthread_mutex_lock(&sbamtx); 927 1.44 pooka TAILQ_INSERT_TAIL(&wrklist, sba, sba_entries); 928 1.44 pooka nwork++; 929 1.44 pooka if (nwork <= idleworker) { 930 1.44 pooka /* do we have a daemon's tool (i.e. idle threads)? */ 931 1.44 pooka pthread_cond_signal(&sbacv); 932 1.44 pooka } else if (nworker < rumpsp_maxworker) { 933 1.44 pooka /* 934 1.44 pooka * Else, need to create one 935 1.44 pooka * (if we can, otherwise just expect another 936 1.44 pooka * worker to pick up the syscall) 937 1.44 pooka */ 938 1.44 pooka if (pthread_create(&pt, &pattr_detached, 939 1.44 pooka serv_workbouncer, NULL) == 0) { 940 1.44 pooka nworker++; 941 1.44 pooka } 942 1.44 pooka } 943 1.44 pooka pthread_mutex_unlock(&sbamtx); 944 1.44 pooka } 945 1.44 pooka 946 1.1 pooka /* 947 1.1 pooka * 948 1.1 pooka * Startup routines and mainloop for server. 949 1.1 pooka * 950 1.1 pooka */ 951 1.1 pooka 952 1.1 pooka struct spservarg { 953 1.1 pooka int sps_sock; 954 1.1 pooka connecthook_fn sps_connhook; 955 1.1 pooka }; 956 1.1 pooka 957 1.7 pooka static void 958 1.7 pooka handlereq(struct spclient *spc) 959 1.7 pooka { 960 1.41 pooka uint64_t reqno; 961 1.55 pooka int error; 962 1.27 pooka 963 1.41 pooka reqno = spc->spc_hdr.rsp_reqno; 964 1.27 pooka if (__predict_false(spc->spc_state == SPCSTATE_NEW)) { 965 1.27 pooka if (spc->spc_hdr.rsp_type != RUMPSP_HANDSHAKE) { 966 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_AUTH); 967 1.29 pooka shutdown(spc->spc_fd, SHUT_RDWR); 968 1.27 pooka spcfreebuf(spc); 969 1.27 pooka return; 970 1.27 pooka } 971 1.27 pooka 972 1.29 pooka if (spc->spc_hdr.rsp_handshake == HANDSHAKE_GUEST) { 973 1.67 pooka /* make sure we fork off of proc1 */ 974 1.67 pooka _DIAGASSERT(lwproc_curlwp() == NULL); 975 1.67 pooka 976 1.77 christos if ((error = lwproc_rfork(spc, RUMP_RFFD_CLEAR, 977 1.77 christos (const char *)spc->spc_buf)) != 0) { 978 1.29 pooka shutdown(spc->spc_fd, SHUT_RDWR); 979 1.29 pooka } 980 1.29 pooka 981 1.29 pooka spcfreebuf(spc); 982 1.29 pooka if (error) 983 1.29 pooka return; 984 1.29 pooka 985 1.29 pooka spc->spc_mainlwp = lwproc_curlwp(); 986 1.29 pooka 987 1.41 pooka send_handshake_resp(spc, reqno, 0); 988 1.29 pooka } else if (spc->spc_hdr.rsp_handshake == HANDSHAKE_FORK) { 989 1.29 pooka struct lwp *tmpmain; 990 1.29 pooka struct prefork *pf; 991 1.29 pooka struct handshake_fork *rfp; 992 1.29 pooka int cancel; 993 1.29 pooka 994 1.29 pooka if (spc->spc_off-HDRSZ != sizeof(*rfp)) { 995 1.48 pooka send_error_resp(spc, reqno, 996 1.48 pooka RUMPSP_ERR_MALFORMED_REQUEST); 997 1.29 pooka shutdown(spc->spc_fd, SHUT_RDWR); 998 1.29 pooka spcfreebuf(spc); 999 1.29 pooka return; 1000 1.29 pooka } 1001 1.29 pooka 1002 1.29 pooka /*LINTED*/ 1003 1.29 pooka rfp = (void *)spc->spc_buf; 1004 1.29 pooka cancel = rfp->rf_cancel; 1005 1.29 pooka 1006 1.29 pooka pthread_mutex_lock(&pfmtx); 1007 1.29 pooka LIST_FOREACH(pf, &preforks, pf_entries) { 1008 1.29 pooka if (memcmp(rfp->rf_auth, pf->pf_auth, 1009 1.29 pooka sizeof(rfp->rf_auth)) == 0) { 1010 1.29 pooka LIST_REMOVE(pf, pf_entries); 1011 1.29 pooka LIST_REMOVE(pf, pf_spcentries); 1012 1.29 pooka break; 1013 1.29 pooka } 1014 1.29 pooka } 1015 1.63 pooka pthread_mutex_unlock(&pfmtx); 1016 1.29 pooka spcfreebuf(spc); 1017 1.29 pooka 1018 1.29 pooka if (!pf) { 1019 1.48 pooka send_error_resp(spc, reqno, 1020 1.48 pooka RUMPSP_ERR_INVALID_PREFORK); 1021 1.29 pooka shutdown(spc->spc_fd, SHUT_RDWR); 1022 1.29 pooka return; 1023 1.29 pooka } 1024 1.29 pooka 1025 1.29 pooka tmpmain = pf->pf_lwp; 1026 1.29 pooka free(pf); 1027 1.29 pooka lwproc_switch(tmpmain); 1028 1.29 pooka if (cancel) { 1029 1.29 pooka lwproc_release(); 1030 1.29 pooka shutdown(spc->spc_fd, SHUT_RDWR); 1031 1.29 pooka return; 1032 1.29 pooka } 1033 1.29 pooka 1034 1.29 pooka /* 1035 1.29 pooka * So, we forked already during "prefork" to save 1036 1.29 pooka * the file descriptors from a parent exit 1037 1.29 pooka * race condition. But now we need to fork 1038 1.29 pooka * a second time since the initial fork has 1039 1.29 pooka * the wrong spc pointer. (yea, optimize 1040 1.29 pooka * interfaces some day if anyone cares) 1041 1.29 pooka */ 1042 1.67 pooka if ((error = lwproc_rfork(spc, 1043 1.67 pooka RUMP_RFFD_SHARE, NULL)) != 0) { 1044 1.48 pooka send_error_resp(spc, reqno, 1045 1.48 pooka RUMPSP_ERR_RFORK_FAILED); 1046 1.29 pooka shutdown(spc->spc_fd, SHUT_RDWR); 1047 1.29 pooka lwproc_release(); 1048 1.29 pooka return; 1049 1.29 pooka } 1050 1.29 pooka spc->spc_mainlwp = lwproc_curlwp(); 1051 1.29 pooka lwproc_switch(tmpmain); 1052 1.29 pooka lwproc_release(); 1053 1.29 pooka lwproc_switch(spc->spc_mainlwp); 1054 1.29 pooka 1055 1.29 pooka send_handshake_resp(spc, reqno, 0); 1056 1.44 pooka } else { 1057 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_AUTH); 1058 1.44 pooka shutdown(spc->spc_fd, SHUT_RDWR); 1059 1.44 pooka spcfreebuf(spc); 1060 1.44 pooka return; 1061 1.29 pooka } 1062 1.29 pooka 1063 1.29 pooka spc->spc_pid = lwproc_getpid(); 1064 1.29 pooka 1065 1.29 pooka DPRINTF(("rump_sp: handshake for client %p complete, pid %d\n", 1066 1.29 pooka spc, spc->spc_pid)); 1067 1.29 pooka 1068 1.29 pooka lwproc_switch(NULL); 1069 1.29 pooka spc->spc_state = SPCSTATE_RUNNING; 1070 1.29 pooka return; 1071 1.29 pooka } 1072 1.29 pooka 1073 1.29 pooka if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_PREFORK)) { 1074 1.29 pooka struct prefork *pf; 1075 1.29 pooka uint32_t auth[AUTHLEN]; 1076 1.57 pooka size_t randlen; 1077 1.44 pooka int inexec; 1078 1.29 pooka 1079 1.29 pooka DPRINTF(("rump_sp: prefork handler executing for %p\n", spc)); 1080 1.27 pooka spcfreebuf(spc); 1081 1.29 pooka 1082 1.44 pooka pthread_mutex_lock(&spc->spc_mtx); 1083 1.44 pooka inexec = spc->spc_inexec; 1084 1.44 pooka pthread_mutex_unlock(&spc->spc_mtx); 1085 1.44 pooka if (inexec) { 1086 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC); 1087 1.44 pooka shutdown(spc->spc_fd, SHUT_RDWR); 1088 1.44 pooka return; 1089 1.44 pooka } 1090 1.44 pooka 1091 1.29 pooka pf = malloc(sizeof(*pf)); 1092 1.29 pooka if (pf == NULL) { 1093 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_NOMEM); 1094 1.29 pooka return; 1095 1.29 pooka } 1096 1.29 pooka 1097 1.29 pooka /* 1098 1.29 pooka * Use client main lwp to fork. this is never used by 1099 1.44 pooka * worker threads (except in exec, but we checked for that 1100 1.44 pooka * above) so we can safely use it here. 1101 1.29 pooka */ 1102 1.29 pooka lwproc_switch(spc->spc_mainlwp); 1103 1.67 pooka if ((error = lwproc_rfork(spc, RUMP_RFFD_COPY, NULL)) != 0) { 1104 1.29 pooka DPRINTF(("rump_sp: fork failed: %d (%p)\n",error, spc)); 1105 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_RFORK_FAILED); 1106 1.29 pooka lwproc_switch(NULL); 1107 1.29 pooka free(pf); 1108 1.27 pooka return; 1109 1.27 pooka } 1110 1.29 pooka 1111 1.29 pooka /* Ok, we have a new process context and a new curlwp */ 1112 1.57 pooka rumpuser_getrandom(auth, sizeof(auth), 0, &randlen); 1113 1.54 pooka memcpy(pf->pf_auth, auth, sizeof(pf->pf_auth)); 1114 1.29 pooka pf->pf_lwp = lwproc_curlwp(); 1115 1.29 pooka lwproc_switch(NULL); 1116 1.29 pooka 1117 1.29 pooka pthread_mutex_lock(&pfmtx); 1118 1.29 pooka LIST_INSERT_HEAD(&preforks, pf, pf_entries); 1119 1.29 pooka LIST_INSERT_HEAD(&spc->spc_pflist, pf, pf_spcentries); 1120 1.29 pooka pthread_mutex_unlock(&pfmtx); 1121 1.29 pooka 1122 1.29 pooka DPRINTF(("rump_sp: prefork handler success %p\n", spc)); 1123 1.29 pooka 1124 1.29 pooka send_prefork_resp(spc, reqno, auth); 1125 1.27 pooka return; 1126 1.27 pooka } 1127 1.7 pooka 1128 1.41 pooka if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_HANDSHAKE)) { 1129 1.44 pooka int inexec; 1130 1.41 pooka 1131 1.41 pooka if (spc->spc_hdr.rsp_handshake != HANDSHAKE_EXEC) { 1132 1.48 pooka send_error_resp(spc, reqno, 1133 1.48 pooka RUMPSP_ERR_MALFORMED_REQUEST); 1134 1.44 pooka shutdown(spc->spc_fd, SHUT_RDWR); 1135 1.41 pooka spcfreebuf(spc); 1136 1.41 pooka return; 1137 1.41 pooka } 1138 1.41 pooka 1139 1.44 pooka pthread_mutex_lock(&spc->spc_mtx); 1140 1.44 pooka inexec = spc->spc_inexec; 1141 1.44 pooka pthread_mutex_unlock(&spc->spc_mtx); 1142 1.44 pooka if (inexec) { 1143 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC); 1144 1.44 pooka shutdown(spc->spc_fd, SHUT_RDWR); 1145 1.44 pooka spcfreebuf(spc); 1146 1.44 pooka return; 1147 1.44 pooka } 1148 1.41 pooka 1149 1.44 pooka pthread_mutex_lock(&spc->spc_mtx); 1150 1.44 pooka spc->spc_inexec = 1; 1151 1.44 pooka pthread_mutex_unlock(&spc->spc_mtx); 1152 1.44 pooka 1153 1.44 pooka /* 1154 1.44 pooka * start to drain lwps. we will wait for it to finish 1155 1.44 pooka * in another thread 1156 1.44 pooka */ 1157 1.41 pooka lwproc_switch(spc->spc_mainlwp); 1158 1.44 pooka lwproc_lwpexit(); 1159 1.41 pooka lwproc_switch(NULL); 1160 1.41 pooka 1161 1.44 pooka /* 1162 1.44 pooka * exec has to wait for lwps to drain, so finish it off 1163 1.44 pooka * in another thread 1164 1.44 pooka */ 1165 1.44 pooka schedulework(spc, SBA_EXEC); 1166 1.41 pooka return; 1167 1.41 pooka } 1168 1.41 pooka 1169 1.21 pooka if (__predict_false(spc->spc_hdr.rsp_type != RUMPSP_SYSCALL)) { 1170 1.48 pooka send_error_resp(spc, reqno, RUMPSP_ERR_MALFORMED_REQUEST); 1171 1.21 pooka spcfreebuf(spc); 1172 1.21 pooka return; 1173 1.21 pooka } 1174 1.7 pooka 1175 1.44 pooka schedulework(spc, SBA_SYSCALL); 1176 1.7 pooka } 1177 1.7 pooka 1178 1.1 pooka static void * 1179 1.1 pooka spserver(void *arg) 1180 1.1 pooka { 1181 1.1 pooka struct spservarg *sarg = arg; 1182 1.11 pooka struct spclient *spc; 1183 1.1 pooka unsigned idx; 1184 1.1 pooka int seen; 1185 1.1 pooka int rv; 1186 1.11 pooka unsigned int nfds, maxidx; 1187 1.1 pooka 1188 1.11 pooka for (idx = 0; idx < MAXCLI; idx++) { 1189 1.1 pooka pfdlist[idx].fd = -1; 1190 1.1 pooka pfdlist[idx].events = POLLIN; 1191 1.11 pooka 1192 1.11 pooka spc = &spclist[idx]; 1193 1.11 pooka pthread_mutex_init(&spc->spc_mtx, NULL); 1194 1.11 pooka pthread_cond_init(&spc->spc_cv, NULL); 1195 1.24 pooka spc->spc_fd = -1; 1196 1.1 pooka } 1197 1.24 pooka pfdlist[0].fd = spclist[0].spc_fd = sarg->sps_sock; 1198 1.1 pooka pfdlist[0].events = POLLIN; 1199 1.1 pooka nfds = 1; 1200 1.1 pooka maxidx = 0; 1201 1.1 pooka 1202 1.14 pooka pthread_attr_init(&pattr_detached); 1203 1.14 pooka pthread_attr_setdetachstate(&pattr_detached, PTHREAD_CREATE_DETACHED); 1204 1.46 joerg #if NOTYET 1205 1.19 pooka pthread_attr_setstacksize(&pattr_detached, 32*1024); 1206 1.46 joerg #endif 1207 1.14 pooka 1208 1.20 pooka pthread_mutex_init(&sbamtx, NULL); 1209 1.20 pooka pthread_cond_init(&sbacv, NULL); 1210 1.20 pooka 1211 1.1 pooka DPRINTF(("rump_sp: server mainloop\n")); 1212 1.1 pooka 1213 1.1 pooka for (;;) { 1214 1.18 pooka int discoed; 1215 1.18 pooka 1216 1.11 pooka /* g/c hangarounds (eventually) */ 1217 1.47 pooka discoed = getdisco(); 1218 1.18 pooka while (discoed--) { 1219 1.18 pooka nfds--; 1220 1.18 pooka idx = maxidx; 1221 1.18 pooka while (idx) { 1222 1.18 pooka if (pfdlist[idx].fd != -1) { 1223 1.18 pooka maxidx = idx; 1224 1.18 pooka break; 1225 1.11 pooka } 1226 1.18 pooka idx--; 1227 1.11 pooka } 1228 1.18 pooka DPRINTF(("rump_sp: set maxidx to [%u]\n", 1229 1.18 pooka maxidx)); 1230 1.11 pooka } 1231 1.11 pooka 1232 1.1 pooka DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1)); 1233 1.1 pooka seen = 0; 1234 1.1 pooka rv = poll(pfdlist, maxidx+1, INFTIM); 1235 1.1 pooka assert(maxidx+1 <= MAXCLI); 1236 1.1 pooka assert(rv != 0); 1237 1.1 pooka if (rv == -1) { 1238 1.1 pooka if (errno == EINTR) 1239 1.1 pooka continue; 1240 1.1 pooka fprintf(stderr, "rump_spserver: poll returned %d\n", 1241 1.1 pooka errno); 1242 1.1 pooka break; 1243 1.1 pooka } 1244 1.1 pooka 1245 1.12 pooka for (idx = 0; seen < rv && idx < MAXCLI; idx++) { 1246 1.1 pooka if ((pfdlist[idx].revents & POLLIN) == 0) 1247 1.1 pooka continue; 1248 1.1 pooka 1249 1.1 pooka seen++; 1250 1.1 pooka DPRINTF(("rump_sp: activity at [%u] %d/%d\n", 1251 1.1 pooka idx, seen, rv)); 1252 1.1 pooka if (idx > 0) { 1253 1.11 pooka spc = &spclist[idx]; 1254 1.1 pooka DPRINTF(("rump_sp: mainloop read [%u]\n", idx)); 1255 1.1 pooka switch (readframe(spc)) { 1256 1.1 pooka case 0: 1257 1.1 pooka break; 1258 1.1 pooka case -1: 1259 1.2 pooka serv_handledisco(idx); 1260 1.1 pooka break; 1261 1.1 pooka default: 1262 1.7 pooka switch (spc->spc_hdr.rsp_class) { 1263 1.7 pooka case RUMPSP_RESP: 1264 1.7 pooka kickwaiter(spc); 1265 1.7 pooka break; 1266 1.7 pooka case RUMPSP_REQ: 1267 1.7 pooka handlereq(spc); 1268 1.7 pooka break; 1269 1.7 pooka default: 1270 1.21 pooka send_error_resp(spc, 1271 1.48 pooka spc->spc_hdr.rsp_reqno, 1272 1.48 pooka RUMPSP_ERR_MALFORMED_REQUEST); 1273 1.21 pooka spcfreebuf(spc); 1274 1.7 pooka break; 1275 1.7 pooka } 1276 1.1 pooka break; 1277 1.1 pooka } 1278 1.11 pooka 1279 1.1 pooka } else { 1280 1.1 pooka DPRINTF(("rump_sp: mainloop new connection\n")); 1281 1.11 pooka 1282 1.24 pooka if (__predict_false(spfini)) { 1283 1.24 pooka close(spclist[0].spc_fd); 1284 1.24 pooka serv_shutdown(); 1285 1.24 pooka goto out; 1286 1.24 pooka } 1287 1.24 pooka 1288 1.11 pooka idx = serv_handleconn(pfdlist[0].fd, 1289 1.11 pooka sarg->sps_connhook, nfds == MAXCLI); 1290 1.11 pooka if (idx) 1291 1.11 pooka nfds++; 1292 1.11 pooka if (idx > maxidx) 1293 1.11 pooka maxidx = idx; 1294 1.12 pooka DPRINTF(("rump_sp: maxid now %d\n", maxidx)); 1295 1.1 pooka } 1296 1.1 pooka } 1297 1.1 pooka } 1298 1.1 pooka 1299 1.24 pooka out: 1300 1.1 pooka return NULL; 1301 1.1 pooka } 1302 1.1 pooka 1303 1.25 pooka static unsigned cleanupidx; 1304 1.25 pooka static struct sockaddr *cleanupsa; 1305 1.1 pooka int 1306 1.56 pooka rumpuser_sp_init(const char *url, 1307 1.26 pooka const char *ostype, const char *osrelease, const char *machine) 1308 1.1 pooka { 1309 1.5 pooka pthread_t pt; 1310 1.1 pooka struct spservarg *sarg; 1311 1.1 pooka struct sockaddr *sap; 1312 1.5 pooka char *p; 1313 1.61 pooka unsigned idx = 0; /* XXXgcc */ 1314 1.5 pooka int error, s; 1315 1.5 pooka 1316 1.5 pooka p = strdup(url); 1317 1.57 pooka if (p == NULL) { 1318 1.57 pooka error = ENOMEM; 1319 1.57 pooka goto out; 1320 1.57 pooka } 1321 1.5 pooka error = parseurl(p, &sap, &idx, 1); 1322 1.5 pooka free(p); 1323 1.5 pooka if (error) 1324 1.57 pooka goto out; 1325 1.5 pooka 1326 1.26 pooka snprintf(banner, sizeof(banner), "RUMPSP-%d.%d-%s-%s/%s\n", 1327 1.26 pooka PROTOMAJOR, PROTOMINOR, ostype, osrelease, machine); 1328 1.26 pooka 1329 1.5 pooka s = socket(parsetab[idx].domain, SOCK_STREAM, 0); 1330 1.57 pooka if (s == -1) { 1331 1.57 pooka error = errno; 1332 1.57 pooka goto out; 1333 1.57 pooka } 1334 1.1 pooka 1335 1.5 pooka sarg = malloc(sizeof(*sarg)); 1336 1.5 pooka if (sarg == NULL) { 1337 1.5 pooka close(s); 1338 1.57 pooka error = ENOMEM; 1339 1.57 pooka goto out; 1340 1.5 pooka } 1341 1.5 pooka 1342 1.5 pooka sarg->sps_sock = s; 1343 1.5 pooka sarg->sps_connhook = parsetab[idx].connhook; 1344 1.1 pooka 1345 1.25 pooka cleanupidx = idx; 1346 1.25 pooka cleanupsa = sap; 1347 1.25 pooka 1348 1.5 pooka /* sloppy error recovery */ 1349 1.1 pooka 1350 1.5 pooka /*LINTED*/ 1351 1.47 pooka if (bind(s, sap, parsetab[idx].slen) == -1) { 1352 1.57 pooka error = errno; 1353 1.69 pooka fprintf(stderr, "rump_sp: failed to bind to URL %s\n", url); 1354 1.57 pooka goto out; 1355 1.1 pooka } 1356 1.18 pooka if (listen(s, MAXCLI) == -1) { 1357 1.57 pooka error = errno; 1358 1.5 pooka fprintf(stderr, "rump_sp: server listen failed\n"); 1359 1.57 pooka goto out; 1360 1.1 pooka } 1361 1.1 pooka 1362 1.5 pooka if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) { 1363 1.5 pooka fprintf(stderr, "rump_sp: cannot create wrkr thread\n"); 1364 1.57 pooka goto out; 1365 1.1 pooka } 1366 1.5 pooka pthread_detach(pt); 1367 1.1 pooka 1368 1.57 pooka out: 1369 1.58 pooka ET(error); 1370 1.1 pooka } 1371 1.24 pooka 1372 1.24 pooka void 1373 1.37 pooka rumpuser_sp_fini(void *arg) 1374 1.24 pooka { 1375 1.37 pooka struct spclient *spc = arg; 1376 1.37 pooka register_t retval[2] = {0, 0}; 1377 1.37 pooka 1378 1.42 pooka if (spclist[0].spc_fd) { 1379 1.42 pooka parsetab[cleanupidx].cleanup(cleanupsa); 1380 1.42 pooka } 1381 1.42 pooka 1382 1.37 pooka /* 1383 1.64 pooka * stuff response into the socket, since the rump kernel container 1384 1.64 pooka * is just about to exit 1385 1.37 pooka */ 1386 1.37 pooka if (spc && spc->spc_syscallreq) 1387 1.37 pooka send_syscall_resp(spc, spc->spc_syscallreq, 0, retval); 1388 1.24 pooka 1389 1.24 pooka if (spclist[0].spc_fd) { 1390 1.24 pooka shutdown(spclist[0].spc_fd, SHUT_RDWR); 1391 1.24 pooka spfini = 1; 1392 1.24 pooka } 1393 1.64 pooka 1394 1.64 pooka /* 1395 1.64 pooka * could release thread, but don't bother, since the container 1396 1.64 pooka * will be stone dead in a moment. 1397 1.64 pooka */ 1398 1.24 pooka } 1399