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