2020-05-06 15:44:36 +03:00
|
|
|
/* $NetBSD: rumpuser_sp.c,v 1.77 2020/05/06 12:44:36 christos Exp $ */
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
/*
|
2011-01-05 20:14:50 +03:00
|
|
|
* Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
|
2010-10-28 00:44:49 +04:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sysproxy routines. This provides system RPC support over host sockets.
|
|
|
|
* The most notable limitation is that the client and server must share
|
|
|
|
* the same ABI. This does not mean that they have to be the same
|
|
|
|
* machine or that they need to run the same version of the host OS,
|
|
|
|
* just that they must agree on the data structures. This even *might*
|
|
|
|
* work correctly from one hardware architecture to another.
|
|
|
|
*/
|
|
|
|
|
2012-07-27 13:09:05 +04:00
|
|
|
#include "rumpuser_port.h"
|
|
|
|
|
|
|
|
#if !defined(lint)
|
2020-05-06 15:44:36 +03:00
|
|
|
__RCSID("$NetBSD: rumpuser_sp.c,v 1.77 2020/05/06 12:44:36 christos Exp $");
|
2012-07-27 13:09:05 +04:00
|
|
|
#endif /* !lint */
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2011-01-02 16:01:45 +03:00
|
|
|
#include <rump/rump.h> /* XXX: for rfork flags */
|
2010-10-28 00:44:49 +04:00
|
|
|
#include <rump/rumpuser.h>
|
2012-07-27 13:09:05 +04:00
|
|
|
|
2010-11-24 20:00:10 +03:00
|
|
|
#include "rumpuser_int.h"
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
#include "sp_common.c"
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-29 14:40:54 +03:00
|
|
|
#ifndef MAXCLI
|
2010-11-26 21:51:03 +03:00
|
|
|
#define MAXCLI 256
|
2010-11-29 14:40:54 +03:00
|
|
|
#endif
|
|
|
|
#ifndef MAXWORKER
|
|
|
|
#define MAXWORKER 128
|
|
|
|
#endif
|
|
|
|
#ifndef IDLEWORKER
|
|
|
|
#define IDLEWORKER 16
|
|
|
|
#endif
|
|
|
|
int rumpsp_maxworker = MAXWORKER;
|
|
|
|
int rumpsp_idleworker = IDLEWORKER;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
static struct pollfd pfdlist[MAXCLI];
|
|
|
|
static struct spclient spclist[MAXCLI];
|
2010-11-24 14:40:24 +03:00
|
|
|
static unsigned int disco;
|
2010-12-12 20:10:36 +03:00
|
|
|
static volatile int spfini;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-12-16 15:38:20 +03:00
|
|
|
static char banner[MAXBANNER];
|
|
|
|
|
|
|
|
#define PROTOMAJOR 0
|
2012-09-21 18:33:03 +04:00
|
|
|
#define PROTOMINOR 4
|
2011-01-05 20:14:50 +03:00
|
|
|
|
2012-07-27 13:09:05 +04:00
|
|
|
|
2015-08-16 14:37:39 +03:00
|
|
|
/* either no atomic ops, or we haven't figured out how to use them */
|
|
|
|
#if defined(__linux__) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__OpenBSD__) || defined(__GNU__) || defined(__GLIBC__)
|
2012-07-27 13:09:05 +04:00
|
|
|
static pthread_mutex_t discomtx = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
static void
|
|
|
|
signaldisco(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
pthread_mutex_lock(&discomtx);
|
|
|
|
disco++;
|
|
|
|
pthread_mutex_unlock(&discomtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
getdisco(void)
|
|
|
|
{
|
|
|
|
unsigned int discocnt;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&discomtx);
|
|
|
|
discocnt = disco;
|
|
|
|
disco = 0;
|
|
|
|
pthread_mutex_unlock(&discomtx);
|
|
|
|
|
|
|
|
return discocnt;
|
|
|
|
}
|
|
|
|
|
2012-11-26 21:55:11 +04:00
|
|
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
2012-11-26 21:03:15 +04:00
|
|
|
|
|
|
|
#include <machine/atomic.h>
|
|
|
|
#define signaldisco() atomic_add_int(&disco, 1)
|
|
|
|
#define getdisco() atomic_readandclear_int(&disco)
|
|
|
|
|
2012-07-27 13:09:05 +04:00
|
|
|
#else /* NetBSD */
|
|
|
|
|
|
|
|
#include <sys/atomic.h>
|
|
|
|
#define signaldisco() atomic_inc_uint(&disco)
|
|
|
|
#define getdisco() atomic_swap_uint(&disco, 0)
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
struct prefork {
|
|
|
|
uint32_t pf_auth[AUTHLEN];
|
|
|
|
struct lwp *pf_lwp;
|
|
|
|
|
|
|
|
LIST_ENTRY(prefork) pf_entries; /* global list */
|
|
|
|
LIST_ENTRY(prefork) pf_spcentries; /* linked from forking spc */
|
|
|
|
};
|
|
|
|
static LIST_HEAD(, prefork) preforks = LIST_HEAD_INITIALIZER(preforks);
|
|
|
|
static pthread_mutex_t pfmtx;
|
2010-12-16 15:38:20 +03:00
|
|
|
|
2011-01-06 09:57:14 +03:00
|
|
|
/*
|
|
|
|
* This version is for the server. It's optimized for multiple threads
|
2011-01-10 14:57:53 +03:00
|
|
|
* and is *NOT* reentrant wrt to signals.
|
2011-01-06 09:57:14 +03:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
waitresp(struct spclient *spc, struct respwait *rw)
|
|
|
|
{
|
2011-01-10 22:49:43 +03:00
|
|
|
int spcstate;
|
2011-01-06 09:57:14 +03:00
|
|
|
int rv = 0;
|
|
|
|
|
2011-01-10 22:49:43 +03:00
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
2011-01-06 09:57:14 +03:00
|
|
|
sendunlockl(spc);
|
2011-01-10 14:57:53 +03:00
|
|
|
while (!rw->rw_done && spc->spc_state != SPCSTATE_DYING) {
|
|
|
|
pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
|
2011-01-06 09:57:14 +03:00
|
|
|
}
|
|
|
|
TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
|
2011-01-10 22:49:43 +03:00
|
|
|
spcstate = spc->spc_state;
|
2011-01-06 09:57:14 +03:00
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
|
|
|
|
pthread_cond_destroy(&rw->rw_cv);
|
|
|
|
|
|
|
|
if (rv)
|
|
|
|
return rv;
|
2011-01-10 22:49:43 +03:00
|
|
|
if (spcstate == SPCSTATE_DYING)
|
2011-01-06 09:57:14 +03:00
|
|
|
return ENOTCONN;
|
|
|
|
return rw->rw_error;
|
|
|
|
}
|
|
|
|
|
2010-11-01 16:49:10 +03:00
|
|
|
/*
|
|
|
|
* Manual wrappers, since librump does not have access to the
|
|
|
|
* user namespace wrapped interfaces.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
lwproc_switch(struct lwp *l)
|
|
|
|
{
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
rumpuser__hyp.hyp_lwproc_switch(l);
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lwproc_release(void)
|
|
|
|
{
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
rumpuser__hyp.hyp_lwproc_release();
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-01-28 22:21:28 +03:00
|
|
|
lwproc_rfork(struct spclient *spc, int flags, const char *comm)
|
2010-11-01 16:49:10 +03:00
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
rv = rumpuser__hyp.hyp_lwproc_rfork(spc, flags, comm);
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-11-19 20:09:44 +03:00
|
|
|
static int
|
|
|
|
lwproc_newlwp(pid_t pid)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
rv = rumpuser__hyp.hyp_lwproc_newlwp(pid);
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2010-11-19 20:09:44 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-11-01 16:49:10 +03:00
|
|
|
static struct lwp *
|
|
|
|
lwproc_curlwp(void)
|
|
|
|
{
|
|
|
|
struct lwp *l;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
l = rumpuser__hyp.hyp_lwproc_curlwp();
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2010-11-19 20:09:44 +03:00
|
|
|
static pid_t
|
|
|
|
lwproc_getpid(void)
|
|
|
|
{
|
|
|
|
pid_t p;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
p = rumpuser__hyp.hyp_getpid();
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2010-11-19 20:09:44 +03:00
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
2011-03-08 15:39:28 +03:00
|
|
|
|
2011-02-15 13:37:07 +03:00
|
|
|
static void
|
|
|
|
lwproc_execnotify(const char *comm)
|
|
|
|
{
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
rumpuser__hyp.hyp_execnotify(comm);
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2011-02-15 13:37:07 +03:00
|
|
|
}
|
2010-11-19 20:09:44 +03:00
|
|
|
|
2011-01-12 15:52:16 +03:00
|
|
|
static void
|
2011-03-08 15:39:28 +03:00
|
|
|
lwproc_lwpexit(void)
|
2011-01-12 15:52:16 +03:00
|
|
|
{
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
rumpuser__hyp.hyp_lwpexit();
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2011-01-12 15:52:16 +03:00
|
|
|
}
|
|
|
|
|
2010-11-01 16:49:10 +03:00
|
|
|
static int
|
2013-04-27 20:02:55 +04:00
|
|
|
rumpsyscall(int sysnum, void *data, register_t *regrv)
|
2010-11-01 16:49:10 +03:00
|
|
|
{
|
2013-04-27 20:02:55 +04:00
|
|
|
long retval[2] = {0, 0};
|
2010-11-01 16:49:10 +03:00
|
|
|
int rv;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser__hyp.hyp_schedule();
|
|
|
|
rv = rumpuser__hyp.hyp_syscall(sysnum, data, retval);
|
|
|
|
rumpuser__hyp.hyp_unschedule();
|
2010-11-01 16:49:10 +03:00
|
|
|
|
2013-04-27 20:02:55 +04:00
|
|
|
regrv[0] = retval[0];
|
|
|
|
regrv[1] = retval[1];
|
2010-11-01 16:49:10 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
static uint64_t
|
|
|
|
nextreq(struct spclient *spc)
|
|
|
|
{
|
|
|
|
uint64_t nw;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
nw = spc->spc_nextreq++;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
|
|
|
|
return nw;
|
|
|
|
}
|
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
/*
|
|
|
|
* XXX: we send responses with "blocking" I/O. This is not
|
|
|
|
* ok for the main thread. XXXFIXME
|
|
|
|
*/
|
|
|
|
|
2010-11-29 19:08:03 +03:00
|
|
|
static void
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(struct spclient *spc, uint64_t reqno, enum rumpsp_err error)
|
2010-11-29 19:08:03 +03:00
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[1];
|
2010-11-29 19:08:03 +03:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr);
|
|
|
|
rhdr.rsp_reqno = reqno;
|
|
|
|
rhdr.rsp_class = RUMPSP_ERROR;
|
|
|
|
rhdr.rsp_type = 0;
|
|
|
|
rhdr.rsp_error = error;
|
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
|
2010-11-29 19:08:03 +03:00
|
|
|
sendlock(spc);
|
2011-03-08 18:34:37 +03:00
|
|
|
(void)SENDIOV(spc, iov);
|
2010-11-29 19:08:03 +03:00
|
|
|
sendunlock(spc);
|
|
|
|
}
|
|
|
|
|
2010-12-16 20:05:44 +03:00
|
|
|
static int
|
|
|
|
send_handshake_resp(struct spclient *spc, uint64_t reqno, int error)
|
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[2];
|
2010-12-16 20:05:44 +03:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(error);
|
|
|
|
rhdr.rsp_reqno = reqno;
|
|
|
|
rhdr.rsp_class = RUMPSP_RESP;
|
|
|
|
rhdr.rsp_type = RUMPSP_HANDSHAKE;
|
|
|
|
rhdr.rsp_error = 0;
|
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
IOVPUT(iov[1], error);
|
|
|
|
|
2010-12-16 20:05:44 +03:00
|
|
|
sendlock(spc);
|
2011-03-08 18:34:37 +03:00
|
|
|
rv = SENDIOV(spc, iov);
|
2010-12-16 20:05:44 +03:00
|
|
|
sendunlock(spc);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
static int
|
|
|
|
send_syscall_resp(struct spclient *spc, uint64_t reqno, int error,
|
2010-11-19 18:25:49 +03:00
|
|
|
register_t *retval)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
|
|
|
struct rsp_sysresp sysresp;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[2];
|
2010-11-19 18:25:49 +03:00
|
|
|
int rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp);
|
|
|
|
rhdr.rsp_reqno = reqno;
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_class = RUMPSP_RESP;
|
|
|
|
rhdr.rsp_type = RUMPSP_SYSCALL;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
|
|
|
sysresp.rsys_error = error;
|
2010-11-19 18:25:49 +03:00
|
|
|
memcpy(sysresp.rsys_retval, retval, sizeof(sysresp.rsys_retval));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
IOVPUT(iov[1], sysresp);
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
sendlock(spc);
|
2011-03-08 18:34:37 +03:00
|
|
|
rv = SENDIOV(spc, iov);
|
2010-11-19 18:25:49 +03:00
|
|
|
sendunlock(spc);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
static int
|
|
|
|
send_prefork_resp(struct spclient *spc, uint64_t reqno, uint32_t *auth)
|
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[2];
|
2011-01-05 20:14:50 +03:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + AUTHLEN*sizeof(*auth);
|
|
|
|
rhdr.rsp_reqno = reqno;
|
|
|
|
rhdr.rsp_class = RUMPSP_RESP;
|
|
|
|
rhdr.rsp_type = RUMPSP_PREFORK;
|
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
IOVPUT_WITHSIZE(iov[1], auth, AUTHLEN*sizeof(*auth));
|
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
sendlock(spc);
|
2011-03-08 18:34:37 +03:00
|
|
|
rv = SENDIOV(spc, iov);
|
2011-01-05 20:14:50 +03:00
|
|
|
sendunlock(spc);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
static int
|
2010-11-25 20:59:02 +03:00
|
|
|
copyin_req(struct spclient *spc, const void *remaddr, size_t *dlen,
|
|
|
|
int wantstr, void **resp)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
|
|
|
struct rsp_copydata copydata;
|
2010-11-19 18:25:49 +03:00
|
|
|
struct respwait rw;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[2];
|
2010-11-19 18:25:49 +03:00
|
|
|
int rv;
|
|
|
|
|
2010-11-25 20:59:02 +03:00
|
|
|
DPRINTF(("copyin_req: %zu bytes from %p\n", *dlen, remaddr));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata);
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_class = RUMPSP_REQ;
|
2010-11-25 20:59:02 +03:00
|
|
|
if (wantstr)
|
|
|
|
rhdr.rsp_type = RUMPSP_COPYINSTR;
|
|
|
|
else
|
|
|
|
rhdr.rsp_type = RUMPSP_COPYIN;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
|
|
|
copydata.rcp_addr = __UNCONST(remaddr);
|
2010-11-25 20:59:02 +03:00
|
|
|
copydata.rcp_len = *dlen;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
IOVPUT(iov[1], copydata);
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
putwait(spc, &rw, &rhdr);
|
2011-03-08 18:34:37 +03:00
|
|
|
rv = SENDIOV(spc, iov);
|
2010-11-24 20:00:10 +03:00
|
|
|
if (rv) {
|
|
|
|
unputwait(spc, &rw);
|
|
|
|
return rv;
|
|
|
|
}
|
2010-11-19 18:25:49 +03:00
|
|
|
|
|
|
|
rv = waitresp(spc, &rw);
|
|
|
|
|
|
|
|
DPRINTF(("copyin: response %d\n", rv));
|
|
|
|
|
|
|
|
*resp = rw.rw_data;
|
2010-11-25 20:59:02 +03:00
|
|
|
if (wantstr)
|
|
|
|
*dlen = rw.rw_dlen;
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
send_copyout_req(struct spclient *spc, const void *remaddr,
|
|
|
|
const void *data, size_t dlen)
|
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
|
|
|
struct rsp_copydata copydata;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[3];
|
2010-11-19 18:25:49 +03:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
DPRINTF(("copyout_req (async): %zu bytes to %p\n", dlen, remaddr));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen;
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_reqno = nextreq(spc);
|
|
|
|
rhdr.rsp_class = RUMPSP_REQ;
|
|
|
|
rhdr.rsp_type = RUMPSP_COPYOUT;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
|
|
|
copydata.rcp_addr = __UNCONST(remaddr);
|
|
|
|
copydata.rcp_len = dlen;
|
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
IOVPUT(iov[1], copydata);
|
|
|
|
IOVPUT_WITHSIZE(iov[2], __UNCONST(data), dlen);
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
sendlock(spc);
|
2011-03-08 18:34:37 +03:00
|
|
|
rv = SENDIOV(spc, iov);
|
2010-11-19 18:25:49 +03:00
|
|
|
sendunlock(spc);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-11-19 18:25:49 +03:00
|
|
|
anonmmap_req(struct spclient *spc, size_t howmuch, void **resp)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
2010-11-19 18:25:49 +03:00
|
|
|
struct respwait rw;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[2];
|
2010-11-19 18:25:49 +03:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
DPRINTF(("anonmmap_req: %zu bytes\n", howmuch));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch);
|
2010-11-19 18:25:49 +03:00
|
|
|
rhdr.rsp_class = RUMPSP_REQ;
|
|
|
|
rhdr.rsp_type = RUMPSP_ANONMMAP;
|
2010-10-28 00:44:49 +04:00
|
|
|
rhdr.rsp_sysnum = 0;
|
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
IOVPUT(iov[1], howmuch);
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
putwait(spc, &rw, &rhdr);
|
2011-03-08 18:34:37 +03:00
|
|
|
rv = SENDIOV(spc, iov);
|
2010-11-24 20:00:10 +03:00
|
|
|
if (rv) {
|
|
|
|
unputwait(spc, &rw);
|
|
|
|
return rv;
|
|
|
|
}
|
2010-11-19 18:25:49 +03:00
|
|
|
|
|
|
|
rv = waitresp(spc, &rw);
|
2010-11-24 20:00:10 +03:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
*resp = rw.rw_data;
|
|
|
|
|
|
|
|
DPRINTF(("anonmmap: mapped at %p\n", **(void ***)resp));
|
|
|
|
|
|
|
|
return rv;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2011-01-14 16:12:14 +03:00
|
|
|
static int
|
|
|
|
send_raise_req(struct spclient *spc, int signo)
|
|
|
|
{
|
|
|
|
struct rsp_hdr rhdr;
|
2011-03-08 18:34:37 +03:00
|
|
|
struct iovec iov[1];
|
2011-01-14 16:12:14 +03:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
rhdr.rsp_len = sizeof(rhdr);
|
|
|
|
rhdr.rsp_class = RUMPSP_REQ;
|
|
|
|
rhdr.rsp_type = RUMPSP_RAISE;
|
|
|
|
rhdr.rsp_signo = signo;
|
|
|
|
|
2011-03-08 18:34:37 +03:00
|
|
|
IOVPUT(iov[0], rhdr);
|
|
|
|
|
2011-01-14 16:12:14 +03:00
|
|
|
sendlock(spc);
|
2011-03-08 18:34:37 +03:00
|
|
|
rv = SENDIOV(spc, iov);
|
2011-01-14 16:12:14 +03:00
|
|
|
sendunlock(spc);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
static void
|
2010-11-24 14:40:24 +03:00
|
|
|
spcref(struct spclient *spc)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
spc->spc_refcnt++;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
spcrelease(struct spclient *spc)
|
|
|
|
{
|
|
|
|
int ref;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
ref = --spc->spc_refcnt;
|
2011-03-08 15:39:28 +03:00
|
|
|
if (__predict_false(spc->spc_inexec && ref <= 2))
|
|
|
|
pthread_cond_broadcast(&spc->spc_cv);
|
2010-11-24 14:40:24 +03:00
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
|
|
|
|
if (ref > 0)
|
|
|
|
return;
|
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
DPRINTF(("rump_sp: spcrelease: spc %p fd %d\n", spc, spc->spc_fd));
|
2010-11-24 18:17:46 +03:00
|
|
|
|
2010-11-24 20:00:10 +03:00
|
|
|
_DIAGASSERT(TAILQ_EMPTY(&spc->spc_respwait));
|
2010-11-24 14:40:24 +03:00
|
|
|
_DIAGASSERT(spc->spc_buf == NULL);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
if (spc->spc_mainlwp) {
|
|
|
|
lwproc_switch(spc->spc_mainlwp);
|
|
|
|
lwproc_release();
|
|
|
|
}
|
2010-11-24 14:40:24 +03:00
|
|
|
spc->spc_mainlwp = NULL;
|
|
|
|
|
|
|
|
close(spc->spc_fd);
|
|
|
|
spc->spc_fd = -1;
|
2010-12-16 20:05:44 +03:00
|
|
|
spc->spc_state = SPCSTATE_NEW;
|
2010-11-24 14:40:24 +03:00
|
|
|
|
2012-07-27 13:09:05 +04:00
|
|
|
signaldisco();
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
static void
|
|
|
|
serv_handledisco(unsigned int idx)
|
|
|
|
{
|
|
|
|
struct spclient *spc = &spclist[idx];
|
2011-03-08 15:39:28 +03:00
|
|
|
int dolwpexit;
|
2010-11-24 14:40:24 +03:00
|
|
|
|
|
|
|
DPRINTF(("rump_sp: disconnecting [%u]\n", idx));
|
|
|
|
|
2010-11-24 18:17:46 +03:00
|
|
|
pfdlist[idx].fd = -1;
|
|
|
|
pfdlist[idx].revents = 0;
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
2010-12-16 20:05:44 +03:00
|
|
|
spc->spc_state = SPCSTATE_DYING;
|
2010-11-24 18:17:46 +03:00
|
|
|
kickall(spc);
|
2011-01-06 01:57:01 +03:00
|
|
|
sendunlockl(spc);
|
2011-03-08 15:39:28 +03:00
|
|
|
/* exec uses mainlwp in another thread, but also nuked all lwps */
|
|
|
|
dolwpexit = !spc->spc_inexec;
|
2010-11-24 18:17:46 +03:00
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
2010-11-26 17:37:08 +03:00
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
if (dolwpexit && spc->spc_mainlwp) {
|
2011-01-12 15:52:16 +03:00
|
|
|
lwproc_switch(spc->spc_mainlwp);
|
2011-03-08 15:39:28 +03:00
|
|
|
lwproc_lwpexit();
|
2011-01-12 15:52:16 +03:00
|
|
|
lwproc_switch(NULL);
|
|
|
|
}
|
|
|
|
|
2010-11-26 17:37:08 +03:00
|
|
|
/*
|
|
|
|
* Nobody's going to attempt to send/receive anymore,
|
|
|
|
* so reinit info relevant to that.
|
|
|
|
*/
|
2010-12-01 01:32:01 +03:00
|
|
|
/*LINTED:pointer casts may be ok*/
|
2010-11-26 17:37:08 +03:00
|
|
|
memset((char *)spc + SPC_ZEROFF, 0, sizeof(*spc) - SPC_ZEROFF);
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
spcrelease(spc);
|
|
|
|
}
|
|
|
|
|
2010-12-12 20:10:36 +03:00
|
|
|
static void
|
|
|
|
serv_shutdown(void)
|
|
|
|
{
|
|
|
|
struct spclient *spc;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 1; i < MAXCLI; i++) {
|
|
|
|
spc = &spclist[i];
|
|
|
|
if (spc->spc_fd == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
serv_handledisco(i);
|
|
|
|
|
|
|
|
spcrelease(spc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
static unsigned
|
|
|
|
serv_handleconn(int fd, connecthook_fn connhook, int busy)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
|
|
|
struct sockaddr_storage ss;
|
|
|
|
socklen_t sl = sizeof(ss);
|
2010-11-24 14:40:24 +03:00
|
|
|
int newfd, flags;
|
2010-10-28 00:44:49 +04:00
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
/*LINTED: cast ok */
|
|
|
|
newfd = accept(fd, (struct sockaddr *)&ss, &sl);
|
|
|
|
if (newfd == -1)
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
if (busy) {
|
2010-10-28 00:44:49 +04:00
|
|
|
close(newfd); /* EBUSY */
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
flags = fcntl(newfd, F_GETFL, 0);
|
|
|
|
if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
|
|
|
close(newfd);
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
if (connhook(newfd) != 0) {
|
2010-10-28 00:44:49 +04:00
|
|
|
close(newfd);
|
2010-11-24 14:40:24 +03:00
|
|
|
return 0;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-12-16 15:38:20 +03:00
|
|
|
/* write out a banner for the client */
|
2011-01-10 22:49:43 +03:00
|
|
|
if (send(newfd, banner, strlen(banner), MSG_NOSIGNAL)
|
|
|
|
!= (ssize_t)strlen(banner)) {
|
2010-12-16 15:38:20 +03:00
|
|
|
close(newfd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
/* find empty slot the simple way */
|
|
|
|
for (i = 0; i < MAXCLI; i++) {
|
2010-12-16 20:05:44 +03:00
|
|
|
if (pfdlist[i].fd == -1 && spclist[i].spc_state == SPCSTATE_NEW)
|
2010-10-28 18:37:29 +04:00
|
|
|
break;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2013-07-18 16:28:26 +04:00
|
|
|
/*
|
|
|
|
* Although not finding a slot is impossible (cf. how this routine
|
|
|
|
* is called), the compiler can still think that i == MAXCLI
|
|
|
|
* if this code is either compiled with NDEBUG or the platform
|
|
|
|
* does not use __dead for assert(). Therefore, add an explicit
|
|
|
|
* check to avoid an array-bounds error.
|
|
|
|
*/
|
|
|
|
/* assert(i < MAXCLI); */
|
|
|
|
if (i == MAXCLI)
|
|
|
|
abort();
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
pfdlist[i].fd = newfd;
|
|
|
|
spclist[i].spc_fd = newfd;
|
2010-11-19 18:25:49 +03:00
|
|
|
spclist[i].spc_istatus = SPCSTATUS_BUSY; /* dedicated receiver */
|
2010-11-24 14:40:24 +03:00
|
|
|
spclist[i].spc_refcnt = 1;
|
2010-11-19 18:25:49 +03:00
|
|
|
|
|
|
|
TAILQ_INIT(&spclist[i].spc_respwait);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
DPRINTF(("rump_sp: added new connection fd %d at idx %u\n", newfd, i));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
return i;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data)
|
|
|
|
{
|
2010-11-19 18:25:49 +03:00
|
|
|
register_t retval[2] = {0, 0};
|
2010-10-28 00:44:49 +04:00
|
|
|
int rv, sysnum;
|
|
|
|
|
|
|
|
sysnum = (int)rhdr->rsp_sysnum;
|
|
|
|
DPRINTF(("rump_sp: handling syscall %d from client %d\n",
|
2011-01-05 20:14:50 +03:00
|
|
|
sysnum, spc->spc_pid));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
if (__predict_false((rv = lwproc_newlwp(spc->spc_pid)) != 0)) {
|
|
|
|
retval[0] = -1;
|
|
|
|
send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
|
|
|
|
return;
|
|
|
|
}
|
2011-01-22 16:41:22 +03:00
|
|
|
spc->spc_syscallreq = rhdr->rsp_reqno;
|
2010-11-01 16:49:10 +03:00
|
|
|
rv = rumpsyscall(sysnum, data, retval);
|
2011-01-22 16:41:22 +03:00
|
|
|
spc->spc_syscallreq = 0;
|
2010-11-26 13:59:14 +03:00
|
|
|
lwproc_release();
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2016-09-06 10:45:41 +03:00
|
|
|
DPRINTF(("rump_sp: got return value %d & %"PRIxREGISTER
|
|
|
|
"/%"PRIxREGISTER"\n",
|
|
|
|
rv, retval[0], retval[1]));
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
static void
|
2020-05-06 15:44:36 +03:00
|
|
|
serv_handleexec(struct spclient *spc, struct rsp_hdr *rhdr, const char *comm)
|
2011-03-08 15:39:28 +03:00
|
|
|
{
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
/* one for the connection and one for us */
|
|
|
|
while (spc->spc_refcnt > 2)
|
|
|
|
pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ok, all the threads are dead (or one is still alive and
|
|
|
|
* the connection is dead, in which case this doesn't matter
|
|
|
|
* very much). proceed with exec.
|
|
|
|
*/
|
|
|
|
|
|
|
|
lwproc_switch(spc->spc_mainlwp);
|
|
|
|
lwproc_execnotify(comm);
|
|
|
|
lwproc_switch(NULL);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
spc->spc_inexec = 0;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
send_handshake_resp(spc, rhdr->rsp_reqno, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
enum sbatype { SBA_SYSCALL, SBA_EXEC };
|
|
|
|
|
|
|
|
struct servbouncearg {
|
2010-11-19 18:25:49 +03:00
|
|
|
struct spclient *sba_spc;
|
|
|
|
struct rsp_hdr sba_hdr;
|
2011-03-08 15:39:28 +03:00
|
|
|
enum sbatype sba_type;
|
2010-11-19 18:25:49 +03:00
|
|
|
uint8_t *sba_data;
|
2010-11-29 14:40:54 +03:00
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
TAILQ_ENTRY(servbouncearg) sba_entries;
|
2010-11-19 18:25:49 +03:00
|
|
|
};
|
2010-11-29 14:40:54 +03:00
|
|
|
static pthread_mutex_t sbamtx;
|
|
|
|
static pthread_cond_t sbacv;
|
2011-02-08 14:21:22 +03:00
|
|
|
static int nworker, idleworker, nwork;
|
2011-03-08 15:39:28 +03:00
|
|
|
static TAILQ_HEAD(, servbouncearg) wrklist = TAILQ_HEAD_INITIALIZER(wrklist);
|
2010-11-29 14:40:54 +03:00
|
|
|
|
|
|
|
/*ARGSUSED*/
|
2010-11-19 18:25:49 +03:00
|
|
|
static void *
|
2011-03-08 15:39:28 +03:00
|
|
|
serv_workbouncer(void *arg)
|
2010-11-19 18:25:49 +03:00
|
|
|
{
|
2011-03-08 15:39:28 +03:00
|
|
|
struct servbouncearg *sba;
|
2010-11-29 14:40:54 +03:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
pthread_mutex_lock(&sbamtx);
|
2011-03-08 00:57:15 +03:00
|
|
|
if (__predict_false(idleworker - nwork >= rumpsp_idleworker)) {
|
2010-11-29 14:40:54 +03:00
|
|
|
nworker--;
|
|
|
|
pthread_mutex_unlock(&sbamtx);
|
|
|
|
break;
|
|
|
|
}
|
2011-02-08 14:21:22 +03:00
|
|
|
idleworker++;
|
2011-03-08 15:39:28 +03:00
|
|
|
while (TAILQ_EMPTY(&wrklist)) {
|
2011-02-08 14:21:22 +03:00
|
|
|
_DIAGASSERT(nwork == 0);
|
2010-11-29 14:40:54 +03:00
|
|
|
pthread_cond_wait(&sbacv, &sbamtx);
|
2011-02-08 14:21:22 +03:00
|
|
|
}
|
|
|
|
idleworker--;
|
2010-11-29 14:40:54 +03:00
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
sba = TAILQ_FIRST(&wrklist);
|
|
|
|
TAILQ_REMOVE(&wrklist, sba, sba_entries);
|
2011-02-08 14:21:22 +03:00
|
|
|
nwork--;
|
2010-11-29 14:40:54 +03:00
|
|
|
pthread_mutex_unlock(&sbamtx);
|
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
if (__predict_true(sba->sba_type == SBA_SYSCALL)) {
|
|
|
|
serv_handlesyscall(sba->sba_spc,
|
|
|
|
&sba->sba_hdr, sba->sba_data);
|
|
|
|
} else {
|
|
|
|
_DIAGASSERT(sba->sba_type == SBA_EXEC);
|
|
|
|
serv_handleexec(sba->sba_spc, &sba->sba_hdr,
|
|
|
|
(char *)sba->sba_data);
|
|
|
|
}
|
2010-11-29 14:40:54 +03:00
|
|
|
spcrelease(sba->sba_spc);
|
|
|
|
free(sba->sba_data);
|
|
|
|
free(sba);
|
|
|
|
}
|
2010-11-19 18:25:49 +03:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-11-25 20:59:02 +03:00
|
|
|
static int
|
|
|
|
sp_copyin(void *arg, const void *raddr, void *laddr, size_t *len, int wantstr)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-22 23:42:19 +03:00
|
|
|
struct spclient *spc = arg;
|
2010-11-19 20:47:44 +03:00
|
|
|
void *rdata = NULL; /* XXXuninit */
|
2010-11-24 20:00:10 +03:00
|
|
|
int rv, nlocks;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_unsched(&nlocks, NULL);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-25 20:59:02 +03:00
|
|
|
rv = copyin_req(spc, raddr, len, wantstr, &rdata);
|
2010-11-24 18:17:46 +03:00
|
|
|
if (rv)
|
2010-11-24 20:00:10 +03:00
|
|
|
goto out;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-25 20:59:02 +03:00
|
|
|
memcpy(laddr, rdata, *len);
|
2010-11-19 18:25:49 +03:00
|
|
|
free(rdata);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 20:00:10 +03:00
|
|
|
out:
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_sched(nlocks, NULL);
|
2010-11-24 20:00:10 +03:00
|
|
|
if (rv)
|
2013-04-30 04:03:52 +04:00
|
|
|
rv = EFAULT;
|
2013-04-30 16:39:20 +04:00
|
|
|
ET(rv);
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2010-11-25 20:59:02 +03:00
|
|
|
rumpuser_sp_copyin(void *arg, const void *raddr, void *laddr, size_t len)
|
|
|
|
{
|
2013-04-30 16:39:20 +04:00
|
|
|
int rv;
|
2010-11-25 20:59:02 +03:00
|
|
|
|
2013-04-30 16:39:20 +04:00
|
|
|
rv = sp_copyin(arg, raddr, laddr, &len, 0);
|
|
|
|
ET(rv);
|
2010-11-25 20:59:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rumpuser_sp_copyinstr(void *arg, const void *raddr, void *laddr, size_t *len)
|
|
|
|
{
|
2013-04-30 16:39:20 +04:00
|
|
|
int rv;
|
2010-11-25 20:59:02 +03:00
|
|
|
|
2013-04-30 16:39:20 +04:00
|
|
|
rv = sp_copyin(arg, raddr, laddr, len, 1);
|
|
|
|
ET(rv);
|
2010-11-25 20:59:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-22 23:42:19 +03:00
|
|
|
struct spclient *spc = arg;
|
2010-11-24 20:00:10 +03:00
|
|
|
int nlocks, rv;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_unsched(&nlocks, NULL);
|
2010-11-25 20:59:02 +03:00
|
|
|
rv = send_copyout_req(spc, raddr, laddr, dlen);
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_sched(nlocks, NULL);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 20:00:10 +03:00
|
|
|
if (rv)
|
2013-04-30 04:03:52 +04:00
|
|
|
rv = EFAULT;
|
2013-04-30 16:39:20 +04:00
|
|
|
ET(rv);
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-25 20:59:02 +03:00
|
|
|
int
|
|
|
|
rumpuser_sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
|
|
|
|
{
|
2013-04-30 16:39:20 +04:00
|
|
|
int rv;
|
2010-11-25 20:59:02 +03:00
|
|
|
|
2013-04-30 16:39:20 +04:00
|
|
|
rv = sp_copyout(arg, laddr, raddr, dlen);
|
|
|
|
ET(rv);
|
2010-11-25 20:59:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rumpuser_sp_copyoutstr(void *arg, const void *laddr, void *raddr, size_t *dlen)
|
|
|
|
{
|
2013-04-30 16:39:20 +04:00
|
|
|
int rv;
|
2010-11-25 20:59:02 +03:00
|
|
|
|
2013-04-30 16:39:20 +04:00
|
|
|
rv = sp_copyout(arg, laddr, raddr, *dlen);
|
|
|
|
ET(rv);
|
2010-11-25 20:59:02 +03:00
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
int
|
2010-11-22 23:42:19 +03:00
|
|
|
rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-22 23:42:19 +03:00
|
|
|
struct spclient *spc = arg;
|
2014-12-08 03:12:03 +03:00
|
|
|
void *resp, *rdata = NULL; /* XXXuninit */
|
2010-11-24 20:00:10 +03:00
|
|
|
int nlocks, rv;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_unsched(&nlocks, NULL);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
rv = anonmmap_req(spc, howmuch, &rdata);
|
2010-11-24 20:00:10 +03:00
|
|
|
if (rv) {
|
|
|
|
rv = EFAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
resp = *(void **)rdata;
|
|
|
|
free(rdata);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
if (resp == NULL) {
|
2010-11-24 20:00:10 +03:00
|
|
|
rv = ENOMEM;
|
2010-11-19 18:25:49 +03:00
|
|
|
}
|
2010-10-28 00:44:49 +04:00
|
|
|
|
|
|
|
*addr = resp;
|
2010-11-24 20:00:10 +03:00
|
|
|
|
|
|
|
out:
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_sched(nlocks, NULL);
|
2013-04-30 16:39:20 +04:00
|
|
|
ET(rv);
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2011-01-14 16:12:14 +03:00
|
|
|
int
|
|
|
|
rumpuser_sp_raise(void *arg, int signo)
|
|
|
|
{
|
|
|
|
struct spclient *spc = arg;
|
|
|
|
int rv, nlocks;
|
|
|
|
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_unsched(&nlocks, NULL);
|
2011-01-14 16:12:14 +03:00
|
|
|
rv = send_raise_req(spc, signo);
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpkern_sched(nlocks, NULL);
|
2011-01-14 16:12:14 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
static pthread_attr_t pattr_detached;
|
|
|
|
static void
|
|
|
|
schedulework(struct spclient *spc, enum sbatype sba_type)
|
|
|
|
{
|
|
|
|
struct servbouncearg *sba;
|
|
|
|
pthread_t pt;
|
|
|
|
uint64_t reqno;
|
|
|
|
int retries = 0;
|
|
|
|
|
|
|
|
reqno = spc->spc_hdr.rsp_reqno;
|
|
|
|
while ((sba = malloc(sizeof(*sba))) == NULL) {
|
If we're going to loop, pausing and then retrying malloc() after it
has failed, in the hope that some other thread has free'd some memory,
but we want to bound the number of attempts, it helps if we actually
count them - otherwise we never get nearer to the limit.
In practice, malloc() for a reasonable application on a modern system
almost never fails, so the code containing this bug has probably never
been, and never will be, executed, but just in case, someday.
For this, it isn't clear if the intent was to have 10 retries (ie: 11
attempts) or 10 tries, but as the code said "retries > 10", I am
assuming the former (not that it matters, if the malloc() has failed
10 times in a row, with 10 second pauses between, the chances of an
11th succeeding aren't great).
2020-03-24 17:56:31 +03:00
|
|
|
if (nworker == 0 || retries++ > 10) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_TRYAGAIN);
|
2011-03-08 15:39:28 +03:00
|
|
|
spcfreebuf(spc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* slim chance of more memory? */
|
|
|
|
usleep(10000);
|
|
|
|
}
|
|
|
|
|
|
|
|
sba->sba_spc = spc;
|
|
|
|
sba->sba_type = sba_type;
|
|
|
|
sba->sba_hdr = spc->spc_hdr;
|
|
|
|
sba->sba_data = spc->spc_buf;
|
|
|
|
spcresetbuf(spc);
|
|
|
|
|
|
|
|
spcref(spc);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&sbamtx);
|
|
|
|
TAILQ_INSERT_TAIL(&wrklist, sba, sba_entries);
|
|
|
|
nwork++;
|
|
|
|
if (nwork <= idleworker) {
|
|
|
|
/* do we have a daemon's tool (i.e. idle threads)? */
|
|
|
|
pthread_cond_signal(&sbacv);
|
|
|
|
} else if (nworker < rumpsp_maxworker) {
|
|
|
|
/*
|
|
|
|
* Else, need to create one
|
|
|
|
* (if we can, otherwise just expect another
|
|
|
|
* worker to pick up the syscall)
|
|
|
|
*/
|
|
|
|
if (pthread_create(&pt, &pattr_detached,
|
|
|
|
serv_workbouncer, NULL) == 0) {
|
|
|
|
nworker++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&sbamtx);
|
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Startup routines and mainloop for server.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct spservarg {
|
|
|
|
int sps_sock;
|
|
|
|
connecthook_fn sps_connhook;
|
|
|
|
};
|
|
|
|
|
2010-11-19 18:25:49 +03:00
|
|
|
static void
|
|
|
|
handlereq(struct spclient *spc)
|
|
|
|
{
|
2011-02-15 13:37:07 +03:00
|
|
|
uint64_t reqno;
|
2013-04-27 21:35:10 +04:00
|
|
|
int error;
|
2010-12-16 20:05:44 +03:00
|
|
|
|
2011-02-15 13:37:07 +03:00
|
|
|
reqno = spc->spc_hdr.rsp_reqno;
|
2010-12-16 20:05:44 +03:00
|
|
|
if (__predict_false(spc->spc_state == SPCSTATE_NEW)) {
|
|
|
|
if (spc->spc_hdr.rsp_type != RUMPSP_HANDSHAKE) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_AUTH);
|
2011-01-05 20:14:50 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
2010-12-16 20:05:44 +03:00
|
|
|
spcfreebuf(spc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
if (spc->spc_hdr.rsp_handshake == HANDSHAKE_GUEST) {
|
2014-08-25 18:58:48 +04:00
|
|
|
/* make sure we fork off of proc1 */
|
|
|
|
_DIAGASSERT(lwproc_curlwp() == NULL);
|
|
|
|
|
2020-05-06 15:44:36 +03:00
|
|
|
if ((error = lwproc_rfork(spc, RUMP_RFFD_CLEAR,
|
|
|
|
(const char *)spc->spc_buf)) != 0) {
|
2011-01-05 20:14:50 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
}
|
|
|
|
|
|
|
|
spcfreebuf(spc);
|
|
|
|
if (error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
spc->spc_mainlwp = lwproc_curlwp();
|
|
|
|
|
2011-02-15 13:37:07 +03:00
|
|
|
send_handshake_resp(spc, reqno, 0);
|
2011-01-05 20:14:50 +03:00
|
|
|
} else if (spc->spc_hdr.rsp_handshake == HANDSHAKE_FORK) {
|
|
|
|
struct lwp *tmpmain;
|
|
|
|
struct prefork *pf;
|
|
|
|
struct handshake_fork *rfp;
|
|
|
|
int cancel;
|
|
|
|
|
|
|
|
if (spc->spc_off-HDRSZ != sizeof(*rfp)) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno,
|
|
|
|
RUMPSP_ERR_MALFORMED_REQUEST);
|
2011-01-05 20:14:50 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
spcfreebuf(spc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*LINTED*/
|
|
|
|
rfp = (void *)spc->spc_buf;
|
|
|
|
cancel = rfp->rf_cancel;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&pfmtx);
|
|
|
|
LIST_FOREACH(pf, &preforks, pf_entries) {
|
|
|
|
if (memcmp(rfp->rf_auth, pf->pf_auth,
|
|
|
|
sizeof(rfp->rf_auth)) == 0) {
|
|
|
|
LIST_REMOVE(pf, pf_entries);
|
|
|
|
LIST_REMOVE(pf, pf_spcentries);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-02-28 17:55:36 +04:00
|
|
|
pthread_mutex_unlock(&pfmtx);
|
2011-01-05 20:14:50 +03:00
|
|
|
spcfreebuf(spc);
|
|
|
|
|
|
|
|
if (!pf) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno,
|
|
|
|
RUMPSP_ERR_INVALID_PREFORK);
|
2011-01-05 20:14:50 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpmain = pf->pf_lwp;
|
|
|
|
free(pf);
|
|
|
|
lwproc_switch(tmpmain);
|
|
|
|
if (cancel) {
|
|
|
|
lwproc_release();
|
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* So, we forked already during "prefork" to save
|
|
|
|
* the file descriptors from a parent exit
|
|
|
|
* race condition. But now we need to fork
|
|
|
|
* a second time since the initial fork has
|
|
|
|
* the wrong spc pointer. (yea, optimize
|
|
|
|
* interfaces some day if anyone cares)
|
|
|
|
*/
|
2014-08-25 18:58:48 +04:00
|
|
|
if ((error = lwproc_rfork(spc,
|
|
|
|
RUMP_RFFD_SHARE, NULL)) != 0) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno,
|
|
|
|
RUMPSP_ERR_RFORK_FAILED);
|
2011-01-05 20:14:50 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
lwproc_release();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
spc->spc_mainlwp = lwproc_curlwp();
|
|
|
|
lwproc_switch(tmpmain);
|
|
|
|
lwproc_release();
|
|
|
|
lwproc_switch(spc->spc_mainlwp);
|
|
|
|
|
|
|
|
send_handshake_resp(spc, reqno, 0);
|
2011-03-08 15:39:28 +03:00
|
|
|
} else {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_AUTH);
|
2011-03-08 15:39:28 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
spcfreebuf(spc);
|
|
|
|
return;
|
2011-01-05 20:14:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
spc->spc_pid = lwproc_getpid();
|
|
|
|
|
|
|
|
DPRINTF(("rump_sp: handshake for client %p complete, pid %d\n",
|
|
|
|
spc, spc->spc_pid));
|
|
|
|
|
|
|
|
lwproc_switch(NULL);
|
|
|
|
spc->spc_state = SPCSTATE_RUNNING;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_PREFORK)) {
|
|
|
|
struct prefork *pf;
|
|
|
|
uint32_t auth[AUTHLEN];
|
2013-04-30 04:03:52 +04:00
|
|
|
size_t randlen;
|
2011-03-08 15:39:28 +03:00
|
|
|
int inexec;
|
2011-01-05 20:14:50 +03:00
|
|
|
|
|
|
|
DPRINTF(("rump_sp: prefork handler executing for %p\n", spc));
|
2010-12-16 20:05:44 +03:00
|
|
|
spcfreebuf(spc);
|
2011-01-05 20:14:50 +03:00
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
inexec = spc->spc_inexec;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
if (inexec) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC);
|
2011-03-08 15:39:28 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-01-05 20:14:50 +03:00
|
|
|
pf = malloc(sizeof(*pf));
|
|
|
|
if (pf == NULL) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_NOMEM);
|
2010-12-16 20:05:44 +03:00
|
|
|
return;
|
|
|
|
}
|
2011-01-05 20:14:50 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Use client main lwp to fork. this is never used by
|
2011-03-08 15:39:28 +03:00
|
|
|
* worker threads (except in exec, but we checked for that
|
|
|
|
* above) so we can safely use it here.
|
2011-01-05 20:14:50 +03:00
|
|
|
*/
|
|
|
|
lwproc_switch(spc->spc_mainlwp);
|
2014-08-25 18:58:48 +04:00
|
|
|
if ((error = lwproc_rfork(spc, RUMP_RFFD_COPY, NULL)) != 0) {
|
2011-01-05 20:14:50 +03:00
|
|
|
DPRINTF(("rump_sp: fork failed: %d (%p)\n",error, spc));
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_RFORK_FAILED);
|
2011-01-05 20:14:50 +03:00
|
|
|
lwproc_switch(NULL);
|
|
|
|
free(pf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ok, we have a new process context and a new curlwp */
|
2013-04-30 04:03:52 +04:00
|
|
|
rumpuser_getrandom(auth, sizeof(auth), 0, &randlen);
|
2013-04-27 20:56:29 +04:00
|
|
|
memcpy(pf->pf_auth, auth, sizeof(pf->pf_auth));
|
2011-01-05 20:14:50 +03:00
|
|
|
pf->pf_lwp = lwproc_curlwp();
|
|
|
|
lwproc_switch(NULL);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&pfmtx);
|
|
|
|
LIST_INSERT_HEAD(&preforks, pf, pf_entries);
|
|
|
|
LIST_INSERT_HEAD(&spc->spc_pflist, pf, pf_spcentries);
|
|
|
|
pthread_mutex_unlock(&pfmtx);
|
|
|
|
|
|
|
|
DPRINTF(("rump_sp: prefork handler success %p\n", spc));
|
|
|
|
|
|
|
|
send_prefork_resp(spc, reqno, auth);
|
2010-12-16 20:05:44 +03:00
|
|
|
return;
|
|
|
|
}
|
2010-11-19 18:25:49 +03:00
|
|
|
|
2011-02-15 13:37:07 +03:00
|
|
|
if (__predict_false(spc->spc_hdr.rsp_type == RUMPSP_HANDSHAKE)) {
|
2011-03-08 15:39:28 +03:00
|
|
|
int inexec;
|
2011-02-15 13:37:07 +03:00
|
|
|
|
|
|
|
if (spc->spc_hdr.rsp_handshake != HANDSHAKE_EXEC) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno,
|
|
|
|
RUMPSP_ERR_MALFORMED_REQUEST);
|
2011-03-08 15:39:28 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
2011-02-15 13:37:07 +03:00
|
|
|
spcfreebuf(spc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
inexec = spc->spc_inexec;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
if (inexec) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_INEXEC);
|
2011-03-08 15:39:28 +03:00
|
|
|
shutdown(spc->spc_fd, SHUT_RDWR);
|
|
|
|
spcfreebuf(spc);
|
|
|
|
return;
|
|
|
|
}
|
2011-02-15 13:37:07 +03:00
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
pthread_mutex_lock(&spc->spc_mtx);
|
|
|
|
spc->spc_inexec = 1;
|
|
|
|
pthread_mutex_unlock(&spc->spc_mtx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* start to drain lwps. we will wait for it to finish
|
|
|
|
* in another thread
|
|
|
|
*/
|
2011-02-15 13:37:07 +03:00
|
|
|
lwproc_switch(spc->spc_mainlwp);
|
2011-03-08 15:39:28 +03:00
|
|
|
lwproc_lwpexit();
|
2011-02-15 13:37:07 +03:00
|
|
|
lwproc_switch(NULL);
|
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
/*
|
|
|
|
* exec has to wait for lwps to drain, so finish it off
|
|
|
|
* in another thread
|
|
|
|
*/
|
|
|
|
schedulework(spc, SBA_EXEC);
|
2011-02-15 13:37:07 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-29 19:08:03 +03:00
|
|
|
if (__predict_false(spc->spc_hdr.rsp_type != RUMPSP_SYSCALL)) {
|
2012-09-21 18:33:03 +04:00
|
|
|
send_error_resp(spc, reqno, RUMPSP_ERR_MALFORMED_REQUEST);
|
2010-11-29 19:08:03 +03:00
|
|
|
spcfreebuf(spc);
|
|
|
|
return;
|
|
|
|
}
|
2010-11-19 18:25:49 +03:00
|
|
|
|
2011-03-08 15:39:28 +03:00
|
|
|
schedulework(spc, SBA_SYSCALL);
|
2010-11-19 18:25:49 +03:00
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
static void *
|
|
|
|
spserver(void *arg)
|
|
|
|
{
|
|
|
|
struct spservarg *sarg = arg;
|
2010-11-24 14:40:24 +03:00
|
|
|
struct spclient *spc;
|
2010-10-28 00:44:49 +04:00
|
|
|
unsigned idx;
|
|
|
|
int seen;
|
|
|
|
int rv;
|
2010-11-24 14:40:24 +03:00
|
|
|
unsigned int nfds, maxidx;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
for (idx = 0; idx < MAXCLI; idx++) {
|
2010-10-28 00:44:49 +04:00
|
|
|
pfdlist[idx].fd = -1;
|
|
|
|
pfdlist[idx].events = POLLIN;
|
2010-11-24 14:40:24 +03:00
|
|
|
|
|
|
|
spc = &spclist[idx];
|
|
|
|
pthread_mutex_init(&spc->spc_mtx, NULL);
|
|
|
|
pthread_cond_init(&spc->spc_cv, NULL);
|
2010-12-12 20:10:36 +03:00
|
|
|
spc->spc_fd = -1;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
2010-12-12 20:10:36 +03:00
|
|
|
pfdlist[0].fd = spclist[0].spc_fd = sarg->sps_sock;
|
2010-10-28 00:44:49 +04:00
|
|
|
pfdlist[0].events = POLLIN;
|
|
|
|
nfds = 1;
|
|
|
|
maxidx = 0;
|
|
|
|
|
2010-11-24 23:29:13 +03:00
|
|
|
pthread_attr_init(&pattr_detached);
|
|
|
|
pthread_attr_setdetachstate(&pattr_detached, PTHREAD_CREATE_DETACHED);
|
2012-03-10 01:03:09 +04:00
|
|
|
#if NOTYET
|
2010-11-27 21:30:51 +03:00
|
|
|
pthread_attr_setstacksize(&pattr_detached, 32*1024);
|
2012-03-10 01:03:09 +04:00
|
|
|
#endif
|
2010-11-24 23:29:13 +03:00
|
|
|
|
2010-11-29 14:40:54 +03:00
|
|
|
pthread_mutex_init(&sbamtx, NULL);
|
|
|
|
pthread_cond_init(&sbacv, NULL);
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
DPRINTF(("rump_sp: server mainloop\n"));
|
|
|
|
|
|
|
|
for (;;) {
|
2010-11-26 21:51:03 +03:00
|
|
|
int discoed;
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
/* g/c hangarounds (eventually) */
|
2012-07-27 13:09:05 +04:00
|
|
|
discoed = getdisco();
|
2010-11-26 21:51:03 +03:00
|
|
|
while (discoed--) {
|
|
|
|
nfds--;
|
|
|
|
idx = maxidx;
|
|
|
|
while (idx) {
|
|
|
|
if (pfdlist[idx].fd != -1) {
|
|
|
|
maxidx = idx;
|
|
|
|
break;
|
2010-11-24 14:40:24 +03:00
|
|
|
}
|
2010-11-26 21:51:03 +03:00
|
|
|
idx--;
|
2010-11-24 14:40:24 +03:00
|
|
|
}
|
2010-11-26 21:51:03 +03:00
|
|
|
DPRINTF(("rump_sp: set maxidx to [%u]\n",
|
|
|
|
maxidx));
|
2010-11-24 14:40:24 +03:00
|
|
|
}
|
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1));
|
|
|
|
seen = 0;
|
|
|
|
rv = poll(pfdlist, maxidx+1, INFTIM);
|
|
|
|
assert(maxidx+1 <= MAXCLI);
|
|
|
|
assert(rv != 0);
|
|
|
|
if (rv == -1) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
fprintf(stderr, "rump_spserver: poll returned %d\n",
|
|
|
|
errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-11-24 18:17:46 +03:00
|
|
|
for (idx = 0; seen < rv && idx < MAXCLI; idx++) {
|
2010-10-28 00:44:49 +04:00
|
|
|
if ((pfdlist[idx].revents & POLLIN) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
seen++;
|
|
|
|
DPRINTF(("rump_sp: activity at [%u] %d/%d\n",
|
|
|
|
idx, seen, rv));
|
|
|
|
if (idx > 0) {
|
2010-11-24 14:40:24 +03:00
|
|
|
spc = &spclist[idx];
|
2010-10-28 00:44:49 +04:00
|
|
|
DPRINTF(("rump_sp: mainloop read [%u]\n", idx));
|
|
|
|
switch (readframe(spc)) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case -1:
|
2010-10-28 18:37:29 +04:00
|
|
|
serv_handledisco(idx);
|
2010-10-28 00:44:49 +04:00
|
|
|
break;
|
|
|
|
default:
|
2010-11-19 18:25:49 +03:00
|
|
|
switch (spc->spc_hdr.rsp_class) {
|
|
|
|
case RUMPSP_RESP:
|
|
|
|
kickwaiter(spc);
|
|
|
|
break;
|
|
|
|
case RUMPSP_REQ:
|
|
|
|
handlereq(spc);
|
|
|
|
break;
|
|
|
|
default:
|
2010-11-29 19:08:03 +03:00
|
|
|
send_error_resp(spc,
|
2012-09-21 18:33:03 +04:00
|
|
|
spc->spc_hdr.rsp_reqno,
|
|
|
|
RUMPSP_ERR_MALFORMED_REQUEST);
|
2010-11-29 19:08:03 +03:00
|
|
|
spcfreebuf(spc);
|
2010-11-19 18:25:49 +03:00
|
|
|
break;
|
|
|
|
}
|
2010-10-28 00:44:49 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-11-24 14:40:24 +03:00
|
|
|
|
2010-10-28 00:44:49 +04:00
|
|
|
} else {
|
|
|
|
DPRINTF(("rump_sp: mainloop new connection\n"));
|
2010-11-24 14:40:24 +03:00
|
|
|
|
2010-12-12 20:10:36 +03:00
|
|
|
if (__predict_false(spfini)) {
|
|
|
|
close(spclist[0].spc_fd);
|
|
|
|
serv_shutdown();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2010-11-24 14:40:24 +03:00
|
|
|
idx = serv_handleconn(pfdlist[0].fd,
|
|
|
|
sarg->sps_connhook, nfds == MAXCLI);
|
|
|
|
if (idx)
|
|
|
|
nfds++;
|
|
|
|
if (idx > maxidx)
|
|
|
|
maxidx = idx;
|
2010-11-24 18:17:46 +03:00
|
|
|
DPRINTF(("rump_sp: maxid now %d\n", maxidx));
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-12 20:10:36 +03:00
|
|
|
out:
|
2010-10-28 00:44:49 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-12-12 20:58:28 +03:00
|
|
|
static unsigned cleanupidx;
|
|
|
|
static struct sockaddr *cleanupsa;
|
2010-10-28 00:44:49 +04:00
|
|
|
int
|
2013-04-29 18:51:39 +04:00
|
|
|
rumpuser_sp_init(const char *url,
|
2010-12-16 15:38:20 +03:00
|
|
|
const char *ostype, const char *osrelease, const char *machine)
|
2010-10-28 00:44:49 +04:00
|
|
|
{
|
2010-11-04 23:54:07 +03:00
|
|
|
pthread_t pt;
|
2010-10-28 00:44:49 +04:00
|
|
|
struct spservarg *sarg;
|
|
|
|
struct sockaddr *sap;
|
2010-11-04 23:54:07 +03:00
|
|
|
char *p;
|
2013-11-02 03:22:13 +04:00
|
|
|
unsigned idx = 0; /* XXXgcc */
|
2010-11-04 23:54:07 +03:00
|
|
|
int error, s;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
p = strdup(url);
|
2013-04-30 04:03:52 +04:00
|
|
|
if (p == NULL) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2010-11-04 23:54:07 +03:00
|
|
|
error = parseurl(p, &sap, &idx, 1);
|
|
|
|
free(p);
|
|
|
|
if (error)
|
2013-04-30 04:03:52 +04:00
|
|
|
goto out;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-12-16 15:38:20 +03:00
|
|
|
snprintf(banner, sizeof(banner), "RUMPSP-%d.%d-%s-%s/%s\n",
|
|
|
|
PROTOMAJOR, PROTOMINOR, ostype, osrelease, machine);
|
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
|
2013-04-30 04:03:52 +04:00
|
|
|
if (s == -1) {
|
|
|
|
error = errno;
|
|
|
|
goto out;
|
|
|
|
}
|
2010-11-04 23:54:07 +03:00
|
|
|
|
|
|
|
sarg = malloc(sizeof(*sarg));
|
|
|
|
if (sarg == NULL) {
|
|
|
|
close(s);
|
2013-04-30 04:03:52 +04:00
|
|
|
error = ENOMEM;
|
|
|
|
goto out;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
sarg->sps_sock = s;
|
|
|
|
sarg->sps_connhook = parsetab[idx].connhook;
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-12-12 20:58:28 +03:00
|
|
|
cleanupidx = idx;
|
|
|
|
cleanupsa = sap;
|
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
/* sloppy error recovery */
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
/*LINTED*/
|
2012-07-27 13:09:05 +04:00
|
|
|
if (bind(s, sap, parsetab[idx].slen) == -1) {
|
2013-04-30 04:03:52 +04:00
|
|
|
error = errno;
|
2015-02-04 15:55:47 +03:00
|
|
|
fprintf(stderr, "rump_sp: failed to bind to URL %s\n", url);
|
2013-04-30 04:03:52 +04:00
|
|
|
goto out;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
2010-11-26 21:51:03 +03:00
|
|
|
if (listen(s, MAXCLI) == -1) {
|
2013-04-30 04:03:52 +04:00
|
|
|
error = errno;
|
2010-11-04 23:54:07 +03:00
|
|
|
fprintf(stderr, "rump_sp: server listen failed\n");
|
2013-04-30 04:03:52 +04:00
|
|
|
goto out;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
|
|
|
|
2010-11-04 23:54:07 +03:00
|
|
|
if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) {
|
|
|
|
fprintf(stderr, "rump_sp: cannot create wrkr thread\n");
|
2013-04-30 04:03:52 +04:00
|
|
|
goto out;
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
2010-11-04 23:54:07 +03:00
|
|
|
pthread_detach(pt);
|
2010-10-28 00:44:49 +04:00
|
|
|
|
2013-04-30 04:03:52 +04:00
|
|
|
out:
|
2013-04-30 16:39:20 +04:00
|
|
|
ET(error);
|
2010-10-28 00:44:49 +04:00
|
|
|
}
|
2010-12-12 20:10:36 +03:00
|
|
|
|
|
|
|
void
|
2011-01-22 16:41:22 +03:00
|
|
|
rumpuser_sp_fini(void *arg)
|
2010-12-12 20:10:36 +03:00
|
|
|
{
|
2011-01-22 16:41:22 +03:00
|
|
|
struct spclient *spc = arg;
|
|
|
|
register_t retval[2] = {0, 0};
|
|
|
|
|
2011-02-15 19:10:41 +03:00
|
|
|
if (spclist[0].spc_fd) {
|
|
|
|
parsetab[cleanupidx].cleanup(cleanupsa);
|
|
|
|
}
|
|
|
|
|
2011-01-22 16:41:22 +03:00
|
|
|
/*
|
2014-05-23 15:04:03 +04:00
|
|
|
* stuff response into the socket, since the rump kernel container
|
|
|
|
* is just about to exit
|
2011-01-22 16:41:22 +03:00
|
|
|
*/
|
|
|
|
if (spc && spc->spc_syscallreq)
|
|
|
|
send_syscall_resp(spc, spc->spc_syscallreq, 0, retval);
|
2010-12-12 20:10:36 +03:00
|
|
|
|
|
|
|
if (spclist[0].spc_fd) {
|
|
|
|
shutdown(spclist[0].spc_fd, SHUT_RDWR);
|
|
|
|
spfini = 1;
|
|
|
|
}
|
2014-05-23 15:04:03 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* could release thread, but don't bother, since the container
|
|
|
|
* will be stone dead in a moment.
|
|
|
|
*/
|
2010-12-12 20:10:36 +03:00
|
|
|
}
|