xref: /netbsd-src/sys/rump/librump/rumpkern/rump.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: rump.c,v 1.23 2007/12/08 19:29:52 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/filedesc.h>
32 #include <sys/kauth.h>
33 #include <sys/kmem.h>
34 #include <sys/mount.h>
35 #include <sys/namei.h>
36 #include <sys/queue.h>
37 #include <sys/resourcevar.h>
38 #include <sys/vnode.h>
39 #include <sys/cpu.h>
40 
41 #include <miscfs/specfs/specdev.h>
42 
43 #include "rump_private.h"
44 #include "rumpuser.h"
45 
46 struct proc rump_proc;
47 struct cwdinfo rump_cwdi;
48 struct pstats rump_stats;
49 struct plimit rump_limits;
50 kauth_cred_t rump_cred;
51 struct cpu_info rump_cpu;
52 
53 kmutex_t rump_giantlock;
54 
55 struct fakeblk {
56 	char path[MAXPATHLEN];
57 	LIST_ENTRY(fakeblk) entries;
58 };
59 
60 static LIST_HEAD(, fakeblk) fakeblks = LIST_HEAD_INITIALIZER(fakeblks);
61 
62 static void
63 rump_aiodone_worker(struct work *wk, void *dummy)
64 {
65 	struct buf *bp = (struct buf *)wk;
66 
67 	KASSERT(&bp->b_work == wk);
68 	bp->b_iodone(bp);
69 }
70 
71 void
72 rump_init()
73 {
74 	extern char hostname[];
75 	extern size_t hostnamelen;
76 	struct proc *p;
77 	struct lwp *l;
78 	int error;
79 
80 	l = &lwp0;
81 	p = &rump_proc;
82 	p->p_stats = &rump_stats;
83 	p->p_cwdi = &rump_cwdi;
84 	p->p_limit = &rump_limits;
85 	p->p_pid = 0;
86 	l->l_cred = rump_cred;
87 	l->l_proc = p;
88 	l->l_lid = 1;
89 
90 	rumpvm_init();
91 
92 	rump_limits.pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
93 
94 	/* should be "enough" */
95 	syncdelay = 0;
96 
97 	vfsinit();
98 	bufinit();
99 
100 	rump_sleepers_init();
101 	rumpuser_thrinit();
102 
103 	rumpuser_mutex_recursive_init(&rump_giantlock.kmtx_mtx);
104 
105 	/* aieeeedondest */
106 	if (workqueue_create(&uvm.aiodone_queue, "aiodoned",
107 	    rump_aiodone_worker, NULL, 0, 0, 0))
108 		panic("aiodoned");
109 
110 	rumpuser_gethostname(hostname, MAXHOSTNAMELEN, &error);
111 	hostnamelen = strlen(hostname);
112 }
113 
114 struct mount *
115 rump_mnt_init(struct vfsops *vfsops, int mntflags)
116 {
117 	struct mount *mp;
118 
119 	mp = rumpuser_malloc(sizeof(struct mount), 0);
120 	memset(mp, 0, sizeof(struct mount));
121 
122 	mp->mnt_op = vfsops;
123 	mp->mnt_flag = mntflags;
124 	TAILQ_INIT(&mp->mnt_vnodelist);
125 
126 	mount_initspecific(mp);
127 
128 	return mp;
129 }
130 
131 int
132 rump_mnt_mount(struct mount *mp, const char *path, void *data, size_t *dlen)
133 {
134 	int rv;
135 
136 	rv = VFS_MOUNT(mp, path, data, dlen);
137 	if (rv)
138 		return rv;
139 
140 	rv = VFS_STATVFS(mp, &mp->mnt_stat);
141 	if (rv) {
142 		VFS_UNMOUNT(mp, MNT_FORCE);
143 		return rv;
144 	}
145 
146 	rv =  VFS_START(mp, 0);
147 	if (rv)
148 		VFS_UNMOUNT(mp, MNT_FORCE);
149 
150 	return rv;
151 }
152 
153 void
154 rump_mnt_destroy(struct mount *mp)
155 {
156 
157 	mount_finispecific(mp);
158 	rumpuser_free(mp);
159 }
160 
161 struct componentname *
162 rump_makecn(u_long nameiop, u_long flags, const char *name, size_t namelen,
163 	kauth_cred_t creds, struct lwp *l)
164 {
165 	struct componentname *cnp;
166 
167 	cnp = rumpuser_malloc(sizeof(struct componentname), 0);
168 	memset(cnp, 0, sizeof(struct componentname));
169 
170 	cnp->cn_nameiop = nameiop;
171 	cnp->cn_flags = flags;
172 
173 	cnp->cn_pnbuf = PNBUF_GET();
174 	strcpy(cnp->cn_pnbuf, name);
175 	cnp->cn_nameptr = cnp->cn_pnbuf;
176 	cnp->cn_namelen = namelen;
177 
178 	cnp->cn_cred = creds;
179 
180 	return cnp;
181 }
182 
183 void
184 rump_freecn(struct componentname *cnp, int flags)
185 {
186 
187 	if (flags & RUMPCN_FREECRED)
188 		rump_cred_destroy(cnp->cn_cred);
189 
190 	if (cnp->cn_flags & SAVENAME) {
191 		if (flags & RUMPCN_ISLOOKUP || cnp->cn_flags & SAVESTART)
192 			PNBUF_PUT(cnp->cn_pnbuf);
193 	} else {
194 		PNBUF_PUT(cnp->cn_pnbuf);
195 	}
196 	rumpuser_free(cnp);
197 }
198 
199 int
200 rump_recyclenode(struct vnode *vp)
201 {
202 
203 	return vrecycle(vp, NULL, curlwp);
204 }
205 
206 static struct fakeblk *
207 _rump_fakeblk_find(const char *path)
208 {
209 	char buf[MAXPATHLEN];
210 	struct fakeblk *fblk;
211 	int error;
212 
213 	if (rumpuser_realpath(path, buf, &error) == NULL)
214 		return NULL;
215 
216 	LIST_FOREACH(fblk, &fakeblks, entries)
217 		if (strcmp(fblk->path, buf) == 0)
218 			return fblk;
219 
220 	return NULL;
221 }
222 
223 int
224 rump_fakeblk_register(const char *path)
225 {
226 	char buf[MAXPATHLEN];
227 	struct fakeblk *fblk;
228 	int error;
229 
230 	if (_rump_fakeblk_find(path))
231 		return EEXIST;
232 
233 	if (rumpuser_realpath(path, buf, &error) == NULL)
234 		return error;
235 
236 	fblk = rumpuser_malloc(sizeof(struct fakeblk), 1);
237 	if (fblk == NULL)
238 		return ENOMEM;
239 
240 	strlcpy(fblk->path, buf, MAXPATHLEN);
241 	LIST_INSERT_HEAD(&fakeblks, fblk, entries);
242 
243 	return 0;
244 }
245 
246 int
247 rump_fakeblk_find(const char *path)
248 {
249 
250 	return _rump_fakeblk_find(path) != NULL;
251 }
252 
253 void
254 rump_fakeblk_deregister(const char *path)
255 {
256 	struct fakeblk *fblk;
257 
258 	fblk = _rump_fakeblk_find(path);
259 	if (fblk == NULL)
260 		return;
261 
262 	LIST_REMOVE(fblk, entries);
263 	rumpuser_free(fblk);
264 }
265 
266 void
267 rump_getvninfo(struct vnode *vp, enum vtype *vtype, voff_t *vsize, dev_t *vdev)
268 {
269 
270 	*vtype = vp->v_type;
271 	*vsize = vp->v_size;
272 	if (vp->v_specinfo)
273 		*vdev = vp->v_rdev;
274 	else
275 		*vdev = 0;
276 }
277 
278 struct vfsops *
279 rump_vfslist_iterate(struct vfsops *ops)
280 {
281 
282 	if (ops == NULL)
283 		return LIST_FIRST(&vfs_list);
284 	else
285 		return LIST_NEXT(ops, vfs_list);
286 }
287 
288 struct vfsops *
289 rump_vfs_getopsbyname(const char *name)
290 {
291 
292 	return vfs_getopsbyname(name);
293 }
294 
295 struct vattr*
296 rump_vattr_init()
297 {
298 	struct vattr *vap;
299 
300 	vap = rumpuser_malloc(sizeof(struct vattr), 0);
301 	vattr_null(vap);
302 
303 	return vap;
304 }
305 
306 void
307 rump_vattr_settype(struct vattr *vap, enum vtype vt)
308 {
309 
310 	vap->va_type = vt;
311 }
312 
313 void
314 rump_vattr_setmode(struct vattr *vap, mode_t mode)
315 {
316 
317 	vap->va_mode = mode;
318 }
319 
320 void
321 rump_vattr_setrdev(struct vattr *vap, dev_t dev)
322 {
323 
324 	vap->va_rdev = dev;
325 }
326 
327 void
328 rump_vattr_free(struct vattr *vap)
329 {
330 
331 	rumpuser_free(vap);
332 }
333 
334 void
335 rump_vp_incref(struct vnode *vp)
336 {
337 
338 	++vp->v_usecount;
339 }
340 
341 int
342 rump_vp_getref(struct vnode *vp)
343 {
344 
345 	return vp->v_usecount;
346 }
347 
348 void
349 rump_vp_decref(struct vnode *vp)
350 {
351 
352 	--vp->v_usecount;
353 }
354 
355 struct uio *
356 rump_uio_setup(void *buf, size_t bufsize, off_t offset, enum rump_uiorw rw)
357 {
358 	struct uio *uio;
359 	enum uio_rw uiorw;
360 
361 	switch (rw) {
362 	case RUMPUIO_READ:
363 		uiorw = UIO_READ;
364 		break;
365 	case RUMPUIO_WRITE:
366 		uiorw = UIO_WRITE;
367 		break;
368 	default:
369 		panic("%s: invalid rw %d", __func__, rw);
370 	}
371 
372 	uio = rumpuser_malloc(sizeof(struct uio), 0);
373 	uio->uio_iov = rumpuser_malloc(sizeof(struct iovec), 0);
374 
375 	uio->uio_iov->iov_base = buf;
376 	uio->uio_iov->iov_len = bufsize;
377 
378 	uio->uio_iovcnt = 1;
379 	uio->uio_offset = offset;
380 	uio->uio_resid = bufsize;
381 	uio->uio_rw = uiorw;
382 	uio->uio_vmspace = UIO_VMSPACE_SYS;
383 
384 	return uio;
385 }
386 
387 size_t
388 rump_uio_getresid(struct uio *uio)
389 {
390 
391 	return uio->uio_resid;
392 }
393 
394 off_t
395 rump_uio_getoff(struct uio *uio)
396 {
397 
398 	return uio->uio_offset;
399 }
400 
401 size_t
402 rump_uio_free(struct uio *uio)
403 {
404 	size_t resid;
405 
406 	resid = uio->uio_resid;
407 	rumpuser_free(uio->uio_iov);
408 	rumpuser_free(uio);
409 
410 	return resid;
411 }
412 
413 void
414 rump_vp_lock_exclusive(struct vnode *vp)
415 {
416 
417 	/* we can skip vn_lock() */
418 	VOP_LOCK(vp, LK_EXCLUSIVE);
419 }
420 
421 void
422 rump_vp_lock_shared(struct vnode *vp)
423 {
424 
425 	VOP_LOCK(vp, LK_SHARED);
426 }
427 
428 void
429 rump_vp_unlock(struct vnode *vp)
430 {
431 
432 	VOP_UNLOCK(vp, 0);
433 }
434 
435 int
436 rump_vp_islocked(struct vnode *vp)
437 {
438 
439 	return VOP_ISLOCKED(vp);
440 }
441 
442 int
443 rump_vfs_unmount(struct mount *mp, int mntflags)
444 {
445 
446 	return VFS_UNMOUNT(mp, mntflags);
447 }
448 
449 int
450 rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock)
451 {
452 	int rv;
453 
454 	rv = VFS_ROOT(mp, vpp);
455 	if (rv)
456 		return rv;
457 
458 	if (!lock)
459 		VOP_UNLOCK(*vpp, 0);
460 
461 	return 0;
462 }
463 
464 /* XXX: statvfs is different from system to system */
465 #if 0
466 int
467 rump_vfs_statvfs(struct mount *mp, struct statvfs *sbp)
468 {
469 
470 	return VFS_STATVFS(mp, sbp);
471 }
472 #endif
473 
474 int
475 rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred)
476 {
477 
478 	return VFS_SYNC(mp, wait ? MNT_WAIT : MNT_NOWAIT, cred);
479 }
480 
481 int
482 rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
483 {
484 
485 	return VFS_FHTOVP(mp, fid, vpp);
486 }
487 
488 int
489 rump_vfs_vptofh(struct vnode *vp, struct fid *fid, size_t *fidsize)
490 {
491 
492 	return VFS_VPTOFH(vp, fid, fidsize);
493 }
494 
495 /*ARGSUSED*/
496 void
497 rump_vfs_syncwait(struct mount *mp)
498 {
499 	int n;
500 
501 	n = buf_syncwait();
502 	if (n)
503 		printf("syncwait: unsynced buffers: %d\n", n);
504 }
505 
506 void
507 rump_bioops_sync()
508 {
509 
510 	if (bioopsp)
511 		bioopsp->io_sync(NULL);
512 }
513 
514 struct lwp *
515 rump_setup_curlwp(pid_t pid, lwpid_t lid, int set)
516 {
517 	struct lwp *l;
518 	struct proc *p;
519 
520 	l = kmem_alloc(sizeof(struct lwp), KM_SLEEP);
521 	p = kmem_alloc(sizeof(struct proc), KM_SLEEP);
522 	p->p_stats = &rump_stats;
523 	p->p_cwdi = &rump_cwdi;
524 	p->p_limit = &rump_limits;
525         p->p_pid = pid;
526 	l->l_cred = rump_cred;
527 	l->l_proc = p;
528         l->l_lid = lid;
529 
530 	if (set)
531 		rumpuser_set_curlwp(l);
532 
533 	return l;
534 }
535 
536 void
537 rump_clear_curlwp()
538 {
539 	struct lwp *l;
540 
541 	l = rumpuser_get_curlwp();
542 	kmem_free(l->l_proc, sizeof(struct proc));
543 	kmem_free(l, sizeof(struct lwp));
544 	rumpuser_set_curlwp(NULL);
545 }
546 
547 struct lwp *
548 rump_get_curlwp()
549 {
550 	struct lwp *l;
551 
552 	l = rumpuser_get_curlwp();
553 	if (l == NULL)
554 		l = &lwp0;
555 
556 	return l;
557 }
558 
559 int
560 rump_splfoo()
561 {
562 
563 	if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
564 		rumpuser_rw_enter(&rumpspl, 0);
565 		rumpuser_set_ipl(RUMPUSER_IPL_SPLFOO);
566 	}
567 
568 	return 0;
569 }
570 
571 static void
572 rump_intr_enter(void)
573 {
574 
575 	rumpuser_set_ipl(RUMPUSER_IPL_INTR);
576 	rumpuser_rw_enter(&rumpspl, 1);
577 }
578 
579 static void
580 rump_intr_exit(void)
581 {
582 
583 	rumpuser_rw_exit(&rumpspl);
584 	rumpuser_clear_ipl(RUMPUSER_IPL_INTR);
585 }
586 
587 void
588 rump_splx(int dummy)
589 {
590 
591 	if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
592 		rumpuser_clear_ipl(RUMPUSER_IPL_SPLFOO);
593 		rumpuser_rw_exit(&rumpspl);
594 	}
595 }
596 
597 void
598 rump_biodone(void *arg, size_t count, int error)
599 {
600 	struct buf *bp = arg;
601 
602 	bp->b_resid = bp->b_bcount - count;
603 	KASSERT(bp->b_resid >= 0);
604 	bp->b_error = error;
605 
606 	rump_intr_enter();
607 	biodone(bp);
608 	rump_intr_exit();
609 }
610