rump.c revision 1.77 1 /* $NetBSD: rump.c,v 1.77 2008/12/13 15:37:13 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by Google Summer of Code.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/atomic.h>
32 #include <sys/buf.h>
33 #include <sys/callout.h>
34 #include <sys/cpu.h>
35 #include <sys/filedesc.h>
36 #include <sys/iostat.h>
37 #include <sys/kauth.h>
38 #include <sys/kmem.h>
39 #include <sys/module.h>
40 #include <sys/once.h>
41 #include <sys/percpu.h>
42 #include <sys/queue.h>
43 #include <sys/resourcevar.h>
44 #include <sys/select.h>
45 #include <sys/uidinfo.h>
46 #include <sys/sysctl.h>
47
48 #include <rump/rumpuser.h>
49
50 #include "rump_private.h"
51 #include "rump_net_private.h"
52 #include "rump_vfs_private.h"
53
54 struct proc proc0;
55 struct pstats rump_stats;
56 struct plimit rump_limits;
57 struct cpu_info rump_cpu;
58 struct filedesc rump_filedesc0;
59 struct proclist allproc;
60 char machine[] = "rump";
61 static kauth_cred_t rump_susercred;
62
63 struct rumpuser_mtx *rump_giantlock;
64
65 sigset_t sigcantmask;
66
67 #ifdef RUMP_WITHOUT_THREADS
68 int rump_threads = 0;
69 #else
70 int rump_threads = 1;
71 #endif
72
73 static void
74 rump_aiodone_worker(struct work *wk, void *dummy)
75 {
76 struct buf *bp = (struct buf *)wk;
77
78 KASSERT(&bp->b_work == wk);
79 bp->b_iodone(bp);
80 }
81
82 static int rump_inited;
83 static struct emul emul_rump;
84
85 void __rump_unavailable(void);
86 void __rump_unavailable() {}
87 __weak_alias(rump_net_init,__rump_unavailable);
88 __weak_alias(rump_vfs_init,__rump_unavailable);
89
90 static void
91 pvfsinit_nop(struct proc *p)
92 {
93
94 return;
95 }
96
97 static void
98 pvfsrele_nop(struct proc *p)
99 {
100
101 return;
102 }
103
104 rump_proc_vfs_init_fn rump_proc_vfs_init = pvfsinit_nop;
105 rump_proc_vfs_release_fn rump_proc_vfs_release = pvfsrele_nop;
106
107 int
108 _rump_init(int rump_version)
109 {
110 extern char hostname[];
111 extern size_t hostnamelen;
112 char buf[256];
113 struct proc *p;
114 struct lwp *l;
115 int error;
116
117 /* XXX */
118 if (rump_inited)
119 return 0;
120 rump_inited = 1;
121
122 if (rump_version != RUMP_VERSION) {
123 printf("rump version mismatch, %d vs. %d\n",
124 rump_version, RUMP_VERSION);
125 return EPROGMISMATCH;
126 }
127
128 if (rumpuser_getenv("RUMP_NVNODES", buf, sizeof(buf), &error) == 0) {
129 desiredvnodes = strtoul(buf, NULL, 10);
130 } else {
131 desiredvnodes = 1<<16;
132 }
133 if (rumpuser_getenv("RUMP_THREADS", buf, sizeof(buf), &error) == 0) {
134 rump_threads = *buf != '0';
135 }
136
137 rumpuser_mutex_recursive_init(&rump_giantlock);
138
139 rumpvm_init();
140 rump_sleepers_init();
141 #ifdef RUMP_USE_REAL_KMEM
142 kmem_init();
143 #endif
144
145 kauth_init();
146 rump_susercred = rump_cred_create(0, 0, 0, NULL);
147
148 l = &lwp0;
149 p = &proc0;
150 p->p_stats = &rump_stats;
151 p->p_limit = &rump_limits;
152 p->p_pid = 0;
153 p->p_fd = &rump_filedesc0;
154 p->p_vmspace = &rump_vmspace;
155 p->p_emul = &emul_rump;
156 l->l_cred = rump_cred_suserget();
157 l->l_proc = p;
158 l->l_lid = 1;
159 LIST_INSERT_HEAD(&allproc, p, p_list);
160
161 rump_limits.pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
162 rump_limits.pl_rlimit[RLIMIT_NOFILE].rlim_cur = RLIM_INFINITY;
163 rump_limits.pl_rlimit[RLIMIT_SBSIZE].rlim_cur = RLIM_INFINITY;
164
165 rumpuser_thrinit();
166 callout_startup();
167 callout_init_cpu(&rump_cpu);
168
169 once_init();
170 iostat_init();
171 uid_init();
172 percpu_init();
173 fd_sys_init();
174 module_init();
175 sysctl_init();
176 softint_init(&rump_cpu);
177
178 /* these do nothing if not present */
179 rump_vfs_init();
180 rump_net_init();
181
182 /* aieeeedondest */
183 if (rump_threads) {
184 if (workqueue_create(&uvm.aiodone_queue, "aiodoned",
185 rump_aiodone_worker, NULL, 0, 0, 0))
186 panic("aiodoned");
187 }
188
189 rumpuser_gethostname(hostname, MAXHOSTNAMELEN, &error);
190 hostnamelen = strlen(hostname);
191
192 sigemptyset(&sigcantmask);
193
194 lwp0.l_fd = proc0.p_fd = fd_init(&rump_filedesc0);
195
196 return 0;
197 }
198
199 struct uio *
200 rump_uio_setup(void *buf, size_t bufsize, off_t offset, enum rump_uiorw rw)
201 {
202 struct uio *uio;
203 enum uio_rw uiorw;
204
205 switch (rw) {
206 case RUMPUIO_READ:
207 uiorw = UIO_READ;
208 break;
209 case RUMPUIO_WRITE:
210 uiorw = UIO_WRITE;
211 break;
212 default:
213 panic("%s: invalid rw %d", __func__, rw);
214 }
215
216 uio = kmem_alloc(sizeof(struct uio), KM_SLEEP);
217 uio->uio_iov = kmem_alloc(sizeof(struct iovec), KM_SLEEP);
218
219 uio->uio_iov->iov_base = buf;
220 uio->uio_iov->iov_len = bufsize;
221
222 uio->uio_iovcnt = 1;
223 uio->uio_offset = offset;
224 uio->uio_resid = bufsize;
225 uio->uio_rw = uiorw;
226 uio->uio_vmspace = UIO_VMSPACE_SYS;
227
228 return uio;
229 }
230
231 size_t
232 rump_uio_getresid(struct uio *uio)
233 {
234
235 return uio->uio_resid;
236 }
237
238 off_t
239 rump_uio_getoff(struct uio *uio)
240 {
241
242 return uio->uio_offset;
243 }
244
245 size_t
246 rump_uio_free(struct uio *uio)
247 {
248 size_t resid;
249
250 resid = uio->uio_resid;
251 kmem_free(uio->uio_iov, sizeof(*uio->uio_iov));
252 kmem_free(uio, sizeof(*uio));
253
254 return resid;
255 }
256
257 struct lwp *
258 rump_setup_curlwp(pid_t pid, lwpid_t lid, int set)
259 {
260 struct lwp *l;
261 struct proc *p;
262
263 l = kmem_zalloc(sizeof(struct lwp), KM_SLEEP);
264 if (pid != 0) {
265 p = kmem_zalloc(sizeof(struct proc), KM_SLEEP);
266 rump_proc_vfs_init(p);
267 p->p_stats = &rump_stats;
268 p->p_limit = &rump_limits;
269 p->p_pid = pid;
270 p->p_vmspace = &rump_vmspace;
271 p->p_fd = fd_init(NULL);
272 } else {
273 p = &proc0;
274 }
275
276 l->l_cred = rump_cred_suserget();
277 l->l_proc = p;
278 l->l_lid = lid;
279 l->l_fd = p->p_fd;
280 l->l_mutex = RUMP_LMUTEX_MAGIC;
281 l->l_cpu = &rump_cpu;
282
283 if (set)
284 rumpuser_set_curlwp(l);
285
286 return l;
287 }
288
289 void
290 rump_clear_curlwp()
291 {
292 struct lwp *l;
293
294 l = rumpuser_get_curlwp();
295 if (l->l_proc->p_pid != 0) {
296 fd_free();
297 rump_proc_vfs_release(l->l_proc);
298 rump_cred_destroy(l->l_cred);
299 kmem_free(l->l_proc, sizeof(*l->l_proc));
300 }
301 kmem_free(l, sizeof(*l));
302 rumpuser_set_curlwp(NULL);
303 }
304
305 struct lwp *
306 rump_get_curlwp()
307 {
308 struct lwp *l;
309
310 l = rumpuser_get_curlwp();
311 if (l == NULL)
312 l = &lwp0;
313
314 return l;
315 }
316
317 int
318 rump_splfoo()
319 {
320
321 if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
322 rumpuser_rw_enter(&rumpspl, 0);
323 rumpuser_set_ipl(RUMPUSER_IPL_SPLFOO);
324 }
325
326 return 0;
327 }
328
329 void
330 rump_intr_enter(void)
331 {
332
333 rumpuser_set_ipl(RUMPUSER_IPL_INTR);
334 rumpuser_rw_enter(&rumpspl, 1);
335 }
336
337 void
338 rump_intr_exit(void)
339 {
340
341 rumpuser_rw_exit(&rumpspl);
342 rumpuser_clear_ipl(RUMPUSER_IPL_INTR);
343 }
344
345 void
346 rump_splx(int dummy)
347 {
348
349 if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
350 rumpuser_clear_ipl(RUMPUSER_IPL_SPLFOO);
351 rumpuser_rw_exit(&rumpspl);
352 }
353 }
354
355 kauth_cred_t
356 rump_cred_create(uid_t uid, gid_t gid, size_t ngroups, gid_t *groups)
357 {
358 kauth_cred_t cred;
359 int rv;
360
361 cred = kauth_cred_alloc();
362 kauth_cred_setuid(cred, uid);
363 kauth_cred_seteuid(cred, uid);
364 kauth_cred_setsvuid(cred, uid);
365 kauth_cred_setgid(cred, gid);
366 kauth_cred_setgid(cred, gid);
367 kauth_cred_setegid(cred, gid);
368 kauth_cred_setsvgid(cred, gid);
369 rv = kauth_cred_setgroups(cred, groups, ngroups, 0, UIO_SYSSPACE);
370 /* oh this is silly. and by "this" I mean kauth_cred_setgroups() */
371 assert(rv == 0);
372
373 return cred;
374 }
375
376 void
377 rump_cred_destroy(kauth_cred_t cred)
378 {
379
380 kauth_cred_free(cred);
381 }
382
383 kauth_cred_t
384 rump_cred_suserget()
385 {
386
387 kauth_cred_hold(rump_susercred);
388 return rump_susercred;
389 }
390
391 /* XXX: if they overflow, we're screwed */
392 lwpid_t
393 rump_nextlid()
394 {
395 static unsigned lwpid = 2;
396
397 do {
398 lwpid = atomic_inc_uint_nv(&lwpid);
399 } while (lwpid == 0);
400
401 return (lwpid_t)lwpid;
402 }
403
404 int
405 rump_module_load(struct modinfo **mi)
406 {
407
408 if (!module_compatible((*mi)->mi_version, __NetBSD_Version__))
409 return EPROGMISMATCH;
410
411 return (*mi)->mi_modcmd(MODULE_CMD_INIT, NULL);
412 }
413
414 int _syspuffs_stub(int, int *);
415 int
416 _syspuffs_stub(int fd, int *newfd)
417 {
418
419 return ENODEV;
420 }
421 __weak_alias(syspuffs_glueinit,_syspuffs_stub);
422