Once again, make the rump kernel hypercall layer work on Linux.

This commit is contained in:
pooka 2012-07-27 09:09:05 +00:00
parent 09452c4910
commit 3b3ffd7039
8 changed files with 279 additions and 71 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser.c,v 1.17 2012/06/25 22:32:47 abs Exp $ */
/* $NetBSD: rumpuser.c,v 1.18 2012/07/27 09:09:05 pooka Exp $ */
/*
* Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved.
@ -25,30 +25,24 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include "rumpuser_port.h"
#if !defined(lint)
__RCSID("$NetBSD: rumpuser.c,v 1.17 2012/06/25 22:32:47 abs Exp $");
__RCSID("$NetBSD: rumpuser.c,v 1.18 2012/07/27 09:09:05 pooka Exp $");
#endif /* !lint */
/* thank the maker for this */
#ifdef __linux__
#define _XOPEN_SOURCE 500
#define _BSD_SOURCE
#define _FILE_OFFSET_BITS 64
#include <features.h>
#endif
#include <sys/param.h>
#include <sys/event.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifdef __NetBSD__
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/dkio.h>
#include <sys/sysctl.h>
#include <sys/event.h>
#endif
#include <assert.h>
@ -256,10 +250,16 @@ rumpuser_anonmmap(void *prefaddr, size_t size, int alignbit,
void *rv;
int prot;
#ifndef MAP_ALIGNED
#define MAP_ALIGNED(a) 0
if (alignbit)
fprintf(stderr, "rumpuser_anonmmap: warning, requested "
"alignment not supported by hypervisor\n");
#endif
prot = PROT_READ|PROT_WRITE;
if (exec)
prot |= PROT_EXEC;
/* XXX: MAP_ALIGNED() is not portable */
rv = mmap(prefaddr, size, prot,
MAP_ANON | MAP_ALIGNED(alignbit), -1, 0);
if (rv == MAP_FAILED) {
@ -500,7 +500,24 @@ int
rumpuser_getenv(const char *name, char *buf, size_t blen, int *error)
{
#ifdef __linux__
char *tmp;
*error = 0;
if ((tmp = getenv(name)) != NULL) {
if (strlen(tmp) >= blen) {
*error = ERANGE;
return -1;
}
strcpy(buf, tmp);
return 0;
} else {
*error = ENOENT;
return -1;
}
#else
DOCALL(int, getenv_r(name, buf, blen));
#endif
}
int
@ -550,6 +567,7 @@ rumpuser_seterrno(int error)
errno = error;
}
#ifdef __NetBSD__
int
rumpuser_writewatchfile_setup(int kq, int fd, intptr_t opaque, int *error)
{
@ -592,6 +610,7 @@ rumpuser_writewatchfile_wait(int kq, intptr_t *opaque, int *error)
*opaque = kev.udata;
return rv;
}
#endif
/*
* This is meant for safe debugging prints from the kernel.
@ -629,20 +648,39 @@ rumpuser_kill(int64_t pid, int sig, int *error)
int
rumpuser_getnhostcpu(void)
{
int ncpu;
size_t sz = sizeof(ncpu);
int ncpu = 1;
#ifdef __NetBSD__
if (sysctlbyname("hw.ncpu", &ncpu, &sz, NULL, 0) == -1)
return 1;
return ncpu;
#else
return 1;
size_t sz = sizeof(ncpu);
sysctlbyname("hw.ncpu", &ncpu, &sz, NULL, 0);
#elif __linux__
FILE *fp;
char *line = NULL;
size_t n = 0;
/* If anyone knows a better way, I'm all ears */
if ((fp = fopen("/proc/cpuinfo", "r")) != NULL) {
ncpu = 0;
while (getline(&line, &n, fp) != -1) {
if (strncmp(line,
"processor", sizeof("processor")-1) == 0)
ncpu++;
}
if (ncpu == 0)
ncpu = 1;
free(line);
fclose(fp);
}
#endif
return ncpu;
}
/* XXX: this hypercall needs a better name */
uint32_t
rumpuser_arc4random(void)
{
return arc4random();
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser_daemonize.c,v 1.2 2011/01/22 14:18:55 pooka Exp $ */
/* $NetBSD: rumpuser_daemonize.c,v 1.3 2012/07/27 09:09:05 pooka Exp $ */
/*
* Copyright (c) 2010 Antti Kantee. All Rights Reserved.
@ -25,9 +25,10 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include "rumpuser_port.h"
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_daemonize.c,v 1.2 2011/01/22 14:18:55 pooka Exp $");
__RCSID("$NetBSD: rumpuser_daemonize.c,v 1.3 2012/07/27 09:09:05 pooka Exp $");
#endif /* !lint */
#include <sys/types.h>

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser_dl.c,v 1.7 2011/03/22 22:27:33 pooka Exp $ */
/* $NetBSD: rumpuser_dl.c,v 1.8 2012/07/27 09:09:05 pooka Exp $ */
/*
* Copyright (c) 2009 Antti Kantee. All Rights Reserved.
@ -30,13 +30,16 @@
* Called during rump bootstrap.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: rumpuser_dl.c,v 1.7 2011/03/22 22:27:33 pooka Exp $");
#include "rumpuser_port.h"
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_dl.c,v 1.8 2012/07/27 09:09:05 pooka Exp $");
#endif /* !lint */
#include <sys/types.h>
#include <sys/time.h>
#include <assert.h>
#include <dlfcn.h>
#include <elf.h>
#include <errno.h>
@ -50,7 +53,7 @@ __RCSID("$NetBSD: rumpuser_dl.c,v 1.7 2011/03/22 22:27:33 pooka Exp $");
#include <rump/rumpuser.h>
#if defined(__ELF__) && (defined(__NetBSD__) || defined(__FreeBSD__) \
|| (defined(__sun__) && defined(__svr4__)))
|| (defined(__sun__) && defined(__svr4__))) || defined(__linux__)
static size_t symtabsize = 0, strtabsize = 0;
static size_t symtaboff = 0, strtaboff = 0;
static uint8_t *symtab = NULL;
@ -62,6 +65,12 @@ static unsigned char eident;
#define Elf_Symindx uint32_t
#endif
/*
* Linux ld.so requires a valid handle for dlinfo(), so use the main
* handle. We initialize this variable in rumpuser_dl_bootstrap()
*/
static void *mainhandle;
static void *
reservespace(void *store, size_t *storesize,
size_t storeoff, size_t required)
@ -130,6 +139,18 @@ do { \
#define SYM_GETSIZE() ((eident==ELFCLASS32)?sizeof(Elf32_Sym):sizeof(Elf64_Sym))
/*
* On NetBSD, the dynamic section pointer values seem to be relative to
* the address the dso is mapped at. On Linux, they seem to contain
* the absolute address. I couldn't find anything definite from a quick
* read of the standard and therefore I will not go and figure beyond ifdef.
*/
#ifdef __linux__
#define adjptr(_map_, _ptr_) ((void *)(_ptr_))
#else
#define adjptr(_map_, _ptr_) ((void *)(_map_->l_addr + (_ptr_)))
#endif
static int
getsymbols(struct link_map *map)
{
@ -142,7 +163,7 @@ getsymbols(struct link_map *map)
unsigned i;
if (map->l_addr) {
if (memcmp(map->l_addr, ELFMAG, SELFMAG) != 0)
if (memcmp((void *)map->l_addr, ELFMAG, SELFMAG) != 0)
return ENOEXEC;
eident = *(unsigned char *)(map->l_addr + EI_CLASS);
if (eident != ELFCLASS32 && eident != ELFCLASS64)
@ -176,11 +197,11 @@ getsymbols(struct link_map *map)
switch (ed_tag) {
case DT_SYMTAB:
DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
syms_base = map->l_addr + edptr;
syms_base = adjptr(map, edptr);
break;
case DT_STRTAB:
DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
str_base = map->l_addr + edptr;
str_base = adjptr(map, edptr);
break;
case DT_STRSZ:
DYNn_GETMEMBER(ed_base, i, d_un.d_val, edval);
@ -188,7 +209,7 @@ getsymbols(struct link_map *map)
break;
case DT_HASH:
DYNn_GETMEMBER(ed_base, i, d_un.d_ptr, edptr);
hashtab = (Elf_Symindx *)(map->l_addr + edptr);
hashtab = (Elf_Symindx *)adjptr(map, edptr);
cursymcount = hashtab[1];
break;
case DT_SYMENT:
@ -307,7 +328,8 @@ rumpuser_dl_bootstrap(rump_modinit_fn domodinit,
struct link_map *map, *origmap;
int error;
if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &origmap) == -1) {
mainhandle = dlopen(NULL, RTLD_NOW);
if (dlinfo(mainhandle, RTLD_DI_LINKMAP, &origmap) == -1) {
fprintf(stderr, "warning: rumpuser module bootstrap "
"failed: %s\n", dlerror());
return;
@ -329,7 +351,7 @@ rumpuser_dl_bootstrap(rump_modinit_fn domodinit,
if (strstr(map->l_name, "librump") != NULL)
error = getsymbols(map);
/* this should be the main object */
else if (map->l_addr == NULL && map->l_prev == NULL)
else if (!map->l_addr && map->l_prev == NULL)
error = getsymbols(map);
}
@ -372,7 +394,7 @@ rumpuser_dl_component_init(int type, rump_component_init_fn compinit)
{
struct link_map *map;
if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map) == -1) {
if (dlinfo(mainhandle, RTLD_DI_LINKMAP, &map) == -1) {
fprintf(stderr, "warning: rumpuser module bootstrap "
"failed: %s\n", dlerror());
return;

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser_net.c,v 1.2 2010/11/15 15:23:32 pooka Exp $ */
/* $NetBSD: rumpuser_net.c,v 1.3 2012/07/27 09:09:05 pooka Exp $ */
/*
* Copyright (c) 2008 Antti Kantee. All Rights Reserved.
@ -25,9 +25,14 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
/*
* Purely to satisfy compilation. This module is not expected to work on
* non-NetBSD due to type conflicts.
*/
#include "rumpuser_port.h"
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_net.c,v 1.2 2010/11/15 15:23:32 pooka Exp $");
__RCSID("$NetBSD: rumpuser_net.c,v 1.3 2012/07/27 09:09:05 pooka Exp $");
#endif /* !lint */
#include <sys/types.h>

View File

@ -0,0 +1,76 @@
/* $NetBSD: rumpuser_port.h,v 1.1 2012/07/27 09:09:05 pooka Exp $ */
/*
* Portability header for non-NetBSD platforms.
* Quick & dirty.
* Maybe should try to use the infrastructure in tools/compat instead?
*/
/*
* XXX:
* There is currently no errno translation for the error values reported
* by the hypercall layer.
*/
#ifndef _LIB_LIBRUMPUSER_RUMPUSER_PORT_H_
#define _LIB_LIBRUMPUSER_RUMPUSER_PORT_H_
#ifdef __NetBSD__
#include <sys/cdefs.h>
#endif
#ifdef __linux__
#define _XOPEN_SOURCE 600
#define _BSD_SOURCE
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#include <features.h>
#endif
#include <sys/types.h>
#include <sys/param.h>
#ifndef __RCSID
#define __RCSID(a)
#endif
#ifndef INFTIM
#define INFTIM (-1)
#endif
#ifndef _DIAGASSERT
#define _DIAGASSERT(_p_)
#endif
#ifdef __linux__
#define SA_SETLEN(a,b)
#else /* BSD */
#define SA_SETLEN(_sa_, _len_) ((struct sockaddr *)_sa_)->sa_len = _len_
#endif
#ifndef __predict_true
#define __predict_true(a) a
#define __predict_false(a) a
#endif
#ifndef __dead
#define __dead
#endif
#ifndef __printflike
#define __printflike(a,b)
#endif
#ifndef __arraycount
#define __arraycount(_ar_) (sizeof(_ar_)/sizeof(_ar_[0]))
#endif
#ifndef __UNCONST
#define __UNCONST(_a_) ((void *)(unsigned long)(const void *)(_a_))
#endif
#ifdef __linux__
#define arc4random() random()
#endif
#endif /* _LIB_LIBRUMPUSER_RUMPUSER_PORT_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser_pth.c,v 1.7 2011/02/05 13:51:56 yamt Exp $ */
/* $NetBSD: rumpuser_pth.c,v 1.8 2012/07/27 09:09:05 pooka Exp $ */
/*
* Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved.
@ -25,19 +25,15 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_pth.c,v 1.7 2011/02/05 13:51:56 yamt Exp $");
#endif /* !lint */
#include "rumpuser_port.h"
#ifdef __linux__
#define _XOPEN_SOURCE 500
#define _BSD_SOURCE
#define _FILE_OFFSET_BITS 64
#endif
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_pth.c,v 1.8 2012/07/27 09:09:05 pooka Exp $");
#endif /* !lint */
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
@ -186,6 +182,21 @@ rumpuser_biothread(void *arg)
void
rumpuser_thrinit(kernel_lockfn lockfn, kernel_unlockfn unlockfn, int threads)
{
#ifdef __linux__
/* XXX: there's no rumpuser_bootstrap, so do this here */
uint32_t rv;
int fd;
if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
srandom(time(NULL));
} else {
if (read(fd, &rv, sizeof(rv)) != sizeof(rv))
srandom(time(NULL));
else
srandom(rv);
close(fd);
}
#endif
pthread_mutex_init(&rumpuser_aio_mtx.pthmtx, NULL);
pthread_cond_init(&rumpuser_aio_cv.pthcv, NULL);

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser_sp.c,v 1.46 2012/03/09 21:03:09 joerg Exp $ */
/* $NetBSD: rumpuser_sp.c,v 1.47 2012/07/27 09:09:05 pooka Exp $ */
/*
* Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
@ -34,11 +34,13 @@
* work correctly from one hardware architecture to another.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: rumpuser_sp.c,v 1.46 2012/03/09 21:03:09 joerg Exp $");
#include "rumpuser_port.h"
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_sp.c,v 1.47 2012/07/27 09:09:05 pooka Exp $");
#endif /* !lint */
#include <sys/types.h>
#include <sys/atomic.h>
#include <sys/mman.h>
#include <sys/socket.h>
@ -59,6 +61,7 @@ __RCSID("$NetBSD: rumpuser_sp.c,v 1.46 2012/03/09 21:03:09 joerg Exp $");
#include <rump/rump.h> /* XXX: for rfork flags */
#include <rump/rumpuser.h>
#include "rumpuser_int.h"
#include "sp_common.c"
@ -87,6 +90,42 @@ static char banner[MAXBANNER];
#define PROTOMAJOR 0
#define PROTOMINOR 3
/* how to use atomic ops on Linux? */
#ifdef __linux__
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;
}
#else /* NetBSD */
#include <sys/atomic.h>
#define signaldisco() atomic_inc_uint(&disco)
#define getdisco() atomic_swap_uint(&disco, 0)
#endif
struct prefork {
uint32_t pf_auth[AUTHLEN];
struct lwp *pf_lwp;
@ -505,7 +544,7 @@ spcrelease(struct spclient *spc)
spc->spc_fd = -1;
spc->spc_state = SPCSTATE_NEW;
atomic_inc_uint(&disco);
signaldisco();
}
static void
@ -908,7 +947,7 @@ handlereq(struct spclient *spc)
reqno = spc->spc_hdr.rsp_reqno;
if (__predict_false(spc->spc_state == SPCSTATE_NEW)) {
if (spc->spc_hdr.rsp_type != RUMPSP_HANDSHAKE) {
send_error_resp(spc, reqno, EAUTH);
send_error_resp(spc, reqno, EACCES);
shutdown(spc->spc_fd, SHUT_RDWR);
spcfreebuf(spc);
return;
@ -999,7 +1038,7 @@ handlereq(struct spclient *spc)
send_handshake_resp(spc, reqno, 0);
} else {
send_error_resp(spc, reqno, EAUTH);
send_error_resp(spc, reqno, EACCES);
shutdown(spc->spc_fd, SHUT_RDWR);
spcfreebuf(spc);
return;
@ -1158,7 +1197,7 @@ spserver(void *arg)
int discoed;
/* g/c hangarounds (eventually) */
discoed = atomic_swap_uint(&disco, 0);
discoed = getdisco();
while (discoed--) {
nfds--;
idx = maxidx;
@ -1288,7 +1327,7 @@ rumpuser_sp_init(const char *url, const struct rumpuser_sp_ops *spopsp,
/* sloppy error recovery */
/*LINTED*/
if (bind(s, sap, sap->sa_len) == -1) {
if (bind(s, sap, parsetab[idx].slen) == -1) {
fprintf(stderr, "rump_sp: server bind failed\n");
return errno;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: sp_common.c,v 1.31 2011/03/08 15:34:37 pooka Exp $ */
/* $NetBSD: sp_common.c,v 1.32 2012/07/27 09:09:05 pooka Exp $ */
/*
* Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
@ -29,14 +29,13 @@
* Common client/server sysproxy routines. #included.
*/
#include <sys/cdefs.h>
#include "rumpuser_port.h"
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/syslimits.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@ -46,6 +45,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <poll.h>
#include <pthread.h>
#include <stdarg.h>
@ -55,6 +55,14 @@
#include <string.h>
#include <unistd.h>
/*
* XXX: NetBSD's __unused collides with Linux headers, so we cannot
* define it before we've included everything.
*/
#if !defined(__unused) && defined(__GNUC__)
#define __unused __attribute__((__unused__))
#endif
//#define DEBUG
#ifdef DEBUG
#define DPRINTF(x) mydprintf x
@ -502,7 +510,7 @@ tcp_parse(const char *addr, struct sockaddr **sa, int allow_wildcard)
int port;
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
SA_SETLEN(&sin, sizeof(sin));
sin.sin_family = AF_INET;
p = strchr(addr, ':');
@ -593,7 +601,7 @@ unix_parse(const char *addr, struct sockaddr **sa, int allow_wildcard)
size_t slen;
int savepath = 0;
if (strlen(addr) > sizeof(sun.sun_path))
if (strlen(addr) >= sizeof(sun.sun_path))
return ENAMETOOLONG;
/*
@ -612,16 +620,20 @@ unix_parse(const char *addr, struct sockaddr **sa, int allow_wildcard)
fprintf(stderr, "warning: cannot determine cwd, "
"omitting socket cleanup\n");
} else {
if (strlen(addr) + strlen(mywd) > sizeof(sun.sun_path))
if (strlen(addr)+strlen(mywd)+1 >= sizeof(sun.sun_path))
return ENAMETOOLONG;
strlcpy(sun.sun_path, mywd, sizeof(sun.sun_path));
strlcat(sun.sun_path, "/", sizeof(sun.sun_path));
strcpy(sun.sun_path, mywd);
strcat(sun.sun_path, "/");
savepath = 1;
}
}
strlcat(sun.sun_path, addr, sizeof(sun.sun_path));
strcat(sun.sun_path, addr);
#ifdef __linux__
slen = sizeof(sun);
#else
sun.sun_len = SUN_LEN(&sun);
slen = sun.sun_len+1; /* get the 0 too */
#endif
if (savepath && *parsedurl == '\0') {
snprintf(parsedurl, sizeof(parsedurl),
@ -668,14 +680,18 @@ success(void)
struct {
const char *id;
int domain;
socklen_t slen;
addrparse_fn ap;
connecthook_fn connhook;
cleanup_fn cleanup;
} parsetab[] = {
{ "tcp", PF_INET, tcp_parse, tcp_connecthook, (cleanup_fn)success },
{ "unix", PF_LOCAL, unix_parse, (connecthook_fn)success, unix_cleanup },
{ "tcp6", PF_INET6, (addrparse_fn)notsupp, (connecthook_fn)success,
(cleanup_fn)success },
{ "tcp", PF_INET, sizeof(struct sockaddr_in),
tcp_parse, tcp_connecthook, (cleanup_fn)success },
{ "unix", PF_LOCAL, sizeof(struct sockaddr_un),
unix_parse, (connecthook_fn)success, unix_cleanup },
{ "tcp6", PF_INET6, sizeof(struct sockaddr_in6),
(addrparse_fn)notsupp, (connecthook_fn)success,
(cleanup_fn)success },
};
#define NPARSE (sizeof(parsetab)/sizeof(parsetab[0]))