Home | History | Annotate | Line # | Download | only in rumpvfs
rump_vfs.c revision 1.62
      1 /*	$NetBSD: rump_vfs.c,v 1.62 2010/11/30 15:39:27 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2008 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Finnish Cultural Foundation.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: rump_vfs.c,v 1.62 2010/11/30 15:39:27 pooka Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/buf.h>
     36 #include <sys/conf.h>
     37 #include <sys/evcnt.h>
     38 #include <sys/filedesc.h>
     39 #include <sys/fstrans.h>
     40 #include <sys/lockf.h>
     41 #include <sys/kthread.h>
     42 #include <sys/module.h>
     43 #include <sys/namei.h>
     44 #include <sys/queue.h>
     45 #include <sys/stat.h>
     46 #include <sys/vfs_syscalls.h>
     47 #include <sys/vnode.h>
     48 #include <sys/wapbl.h>
     49 
     50 #include <miscfs/specfs/specdev.h>
     51 #include <miscfs/syncfs/syncfs.h>
     52 
     53 #include <rump/rump.h>
     54 #include <rump/rumpuser.h>
     55 
     56 #include "rump_private.h"
     57 #include "rump_vfs_private.h"
     58 
     59 struct cwdinfo cwdi0;
     60 const char *rootfstype = ROOT_FSTYPE_ANY;
     61 
     62 static void
     63 pvfs_init(struct proc *p)
     64 {
     65 
     66 	p->p_cwdi = cwdinit();
     67 }
     68 
     69 static void
     70 pvfs_rele(struct proc *p)
     71 {
     72 
     73 	cwdfree(p->p_cwdi);
     74 }
     75 
     76 void
     77 rump_vfs_init(void)
     78 {
     79 	extern struct devsw_conv devsw_conv0[];
     80 	extern int max_devsw_convs;
     81 	extern struct vfsops rumpfs_vfsops;
     82 	char buf[64];
     83 	int error;
     84 	int rv, i;
     85 
     86 	if (rumpuser_getenv("RUMP_NVNODES", buf, sizeof(buf), &error) == 0) {
     87 		desiredvnodes = strtoul(buf, NULL, 10);
     88 	} else {
     89 		desiredvnodes = 1<<10;
     90 	}
     91 
     92 	rumpblk_init();
     93 
     94 	for (i = 0; i < ncpu; i++) {
     95 		struct cpu_info *ci = cpu_lookup(i);
     96 		cache_cpu_init(ci);
     97 	}
     98 
     99 	/* make number of bufpages 5% of total memory limit */
    100 	if (rump_physmemlimit != RUMPMEM_UNLIMITED) {
    101 		extern u_int bufpages;
    102 		bufpages = rump_physmemlimit / (20 * PAGE_SIZE);
    103 	}
    104 
    105 	vfsinit();
    106 	bufinit();
    107 	cwd_sys_init();
    108 	lf_init();
    109 	spec_init();
    110 	fstrans_init();
    111 
    112 	if (rump_threads) {
    113 		if ((rv = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL,
    114 		    rumpuser_biothread, rump_biodone, NULL, "rmpabio")) != 0)
    115 			panic("syncer thread create failed: %d", rv);
    116 	}
    117 
    118 	root_device = &rump_rootdev;
    119 
    120 	/* bootstrap cwdi (rest done in vfs_mountroot() */
    121 	rw_init(&cwdi0.cwdi_lock);
    122 	proc0.p_cwdi = &cwdi0;
    123 	proc0.p_cwdi = cwdinit();
    124 
    125 	vfs_attach(&rumpfs_vfsops);
    126 	vfs_mountroot();
    127 
    128 	/* "mtree": create /dev */
    129 	do_sys_mkdir("/dev", 0777, UIO_SYSSPACE);
    130 	rump_devnull_init();
    131 
    132 	rump_proc_vfs_init = pvfs_init;
    133 	rump_proc_vfs_release = pvfs_rele;
    134 
    135 	if (rump_threads) {
    136 		if ((rv = kthread_create(PRI_IOFLUSH, KTHREAD_MPSAFE, NULL,
    137 		    sched_sync, NULL, NULL, "ioflush")) != 0)
    138 			panic("syncer thread create failed: %d", rv);
    139 	} else {
    140 		syncdelay = 0;
    141 	}
    142 
    143 	/*
    144 	 * On archs where the native kernel ABI is supported, map
    145 	 * host module directory to rump.  This means that kernel
    146 	 * modules from the host will be autoloaded to rump kernels.
    147 	 */
    148 #ifdef _RUMP_NATIVE_ABI
    149 	{
    150 	char *mbase;
    151 
    152 	if (rumpuser_getenv("RUMP_MODULEBASE", buf, sizeof(buf), &error) == 0)
    153 		mbase = buf;
    154 	else
    155 		mbase = module_base;
    156 
    157 	if (strlen(mbase) != 0 && *mbase != '0') {
    158 		rump_etfs_register(module_base, mbase, RUMP_ETFS_DIR_SUBDIRS);
    159 	}
    160 	}
    161 #endif
    162 
    163 	module_init_class(MODULE_CLASS_VFS);
    164 
    165 	rump_vfs_builddevs(devsw_conv0, max_devsw_convs);
    166 
    167 	rump_component_init(RUMP_COMPONENT_VFS);
    168 }
    169 
    170 void
    171 rump_vfs_fini(void)
    172 {
    173 
    174 	vfs_shutdown();
    175 }
    176 
    177 struct rumpcn {
    178 	struct componentname rcn_cn;
    179 	char *rcn_path;
    180 };
    181 
    182 struct componentname *
    183 rump_makecn(u_long nameiop, u_long flags, const char *name, size_t namelen,
    184 	kauth_cred_t creds, struct lwp *l)
    185 {
    186 	struct rumpcn *rcn;
    187 	struct componentname *cnp;
    188 	const char *cp = NULL;
    189 
    190 	rcn = kmem_zalloc(sizeof(*rcn), KM_SLEEP);
    191 	cnp = &rcn->rcn_cn;
    192 
    193 	rcn->rcn_path = PNBUF_GET();
    194 	strlcpy(rcn->rcn_path, name, MAXPATHLEN);
    195 	cnp->cn_nameptr = rcn->rcn_path;
    196 
    197 	cnp->cn_nameiop = nameiop;
    198 	cnp->cn_flags = flags;
    199 
    200 	cnp->cn_namelen = namelen;
    201 	cnp->cn_hash = namei_hash(name, &cp);
    202 
    203 	cnp->cn_cred = creds;
    204 
    205 	return cnp;
    206 }
    207 
    208 void
    209 rump_freecn(struct componentname *cnp, int flags)
    210 {
    211 	struct rumpcn *rcn = (void *)cnp;
    212 
    213 	if (flags & RUMPCN_FREECRED)
    214 		rump_cred_put(cnp->cn_cred);
    215 
    216 	PNBUF_PUT(rcn->rcn_path);
    217 	kmem_free(cnp, sizeof(*cnp));
    218 }
    219 
    220 int
    221 rump_checksavecn(struct componentname *cnp)
    222 {
    223 
    224 	if ((cnp->cn_flags & SAVESTART) == 0) {
    225 		return 0;
    226 	} else {
    227 		return 1;
    228 	}
    229 }
    230 
    231 /* hey baby, what's your namei? */
    232 int
    233 rump_namei(uint32_t op, uint32_t flags, const char *namep,
    234 	struct vnode **dvpp, struct vnode **vpp, struct componentname **cnpp)
    235 {
    236 	struct pathbuf *pb;
    237 	struct nameidata nd;
    238 	int rv;
    239 
    240 	pb = pathbuf_create(namep);
    241 	if (pb == NULL) {
    242 		return ENOMEM;
    243 	}
    244 	NDINIT(&nd, op, flags, pb);
    245 	rv = namei(&nd);
    246 	if (rv) {
    247 		pathbuf_destroy(pb);
    248 		return rv;
    249 	}
    250 
    251 	if (dvpp) {
    252 		KASSERT(flags & LOCKPARENT);
    253 		*dvpp = nd.ni_dvp;
    254 	} else {
    255 		KASSERT((flags & LOCKPARENT) == 0);
    256 	}
    257 
    258 	if (vpp) {
    259 		*vpp = nd.ni_vp;
    260 	} else {
    261 		if (nd.ni_vp) {
    262 			if (flags & LOCKLEAF)
    263 				vput(nd.ni_vp);
    264 			else
    265 				vrele(nd.ni_vp);
    266 		}
    267 	}
    268 
    269 	if (cnpp) {
    270 		struct componentname *cnp;
    271 
    272 		cnp = kmem_alloc(sizeof(*cnp), KM_SLEEP);
    273 		memcpy(cnp, &nd.ni_cnd, sizeof(*cnp));
    274 		*cnpp = cnp;
    275 	}
    276 	pathbuf_destroy(pb);
    277 
    278 	return rv;
    279 }
    280 
    281 void
    282 rump_getvninfo(struct vnode *vp, enum vtype *vtype,
    283 	voff_t *vsize, dev_t *vdev)
    284 {
    285 
    286 	*vtype = vp->v_type;
    287 	*vsize = vp->v_size;
    288 	if (vp->v_specnode)
    289 		*vdev = vp->v_rdev;
    290 	else
    291 		*vdev = 0;
    292 }
    293 
    294 struct vfsops *
    295 rump_vfslist_iterate(struct vfsops *ops)
    296 {
    297 
    298 	if (ops == NULL)
    299 		return LIST_FIRST(&vfs_list);
    300 	else
    301 		return LIST_NEXT(ops, vfs_list);
    302 }
    303 
    304 struct vfsops *
    305 rump_vfs_getopsbyname(const char *name)
    306 {
    307 
    308 	return vfs_getopsbyname(name);
    309 }
    310 
    311 int
    312 rump_vfs_getmp(const char *path, struct mount **mpp)
    313 {
    314 	struct vnode *vp;
    315 	int rv;
    316 
    317 	if ((rv = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp)) != 0)
    318 		return rv;
    319 
    320 	*mpp = vp->v_mount;
    321 	vrele(vp);
    322 	return 0;
    323 }
    324 
    325 struct vattr*
    326 rump_vattr_init(void)
    327 {
    328 	struct vattr *vap;
    329 
    330 	vap = kmem_alloc(sizeof(struct vattr), KM_SLEEP);
    331 	vattr_null(vap);
    332 
    333 	return vap;
    334 }
    335 
    336 void
    337 rump_vattr_settype(struct vattr *vap, enum vtype vt)
    338 {
    339 
    340 	vap->va_type = vt;
    341 }
    342 
    343 void
    344 rump_vattr_setmode(struct vattr *vap, mode_t mode)
    345 {
    346 
    347 	vap->va_mode = mode;
    348 }
    349 
    350 void
    351 rump_vattr_setrdev(struct vattr *vap, dev_t dev)
    352 {
    353 
    354 	vap->va_rdev = dev;
    355 }
    356 
    357 void
    358 rump_vattr_free(struct vattr *vap)
    359 {
    360 
    361 	kmem_free(vap, sizeof(*vap));
    362 }
    363 
    364 void
    365 rump_vp_incref(struct vnode *vp)
    366 {
    367 
    368 	vref(vp);
    369 }
    370 
    371 int
    372 rump_vp_getref(struct vnode *vp)
    373 {
    374 
    375 	return vp->v_usecount;
    376 }
    377 
    378 void
    379 rump_vp_rele(struct vnode *vp)
    380 {
    381 
    382 	vrele(vp);
    383 }
    384 
    385 void
    386 rump_vp_interlock(struct vnode *vp)
    387 {
    388 
    389 	mutex_enter(&vp->v_interlock);
    390 }
    391 
    392 int
    393 rump_vfs_unmount(struct mount *mp, int mntflags)
    394 {
    395 
    396 	return VFS_UNMOUNT(mp, mntflags);
    397 }
    398 
    399 int
    400 rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock)
    401 {
    402 	int rv;
    403 
    404 	rv = VFS_ROOT(mp, vpp);
    405 	if (rv)
    406 		return rv;
    407 
    408 	if (!lock)
    409 		VOP_UNLOCK(*vpp);
    410 
    411 	return 0;
    412 }
    413 
    414 int
    415 rump_vfs_statvfs(struct mount *mp, struct statvfs *sbp)
    416 {
    417 
    418 	return VFS_STATVFS(mp, sbp);
    419 }
    420 
    421 int
    422 rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred)
    423 {
    424 
    425 	return VFS_SYNC(mp, wait ? MNT_WAIT : MNT_NOWAIT, cred);
    426 }
    427 
    428 int
    429 rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
    430 {
    431 
    432 	return VFS_FHTOVP(mp, fid, vpp);
    433 }
    434 
    435 int
    436 rump_vfs_vptofh(struct vnode *vp, struct fid *fid, size_t *fidsize)
    437 {
    438 
    439 	return VFS_VPTOFH(vp, fid, fidsize);
    440 }
    441 
    442 int
    443 rump_vfs_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
    444 	int attrnamespace, const char *attrname)
    445 {
    446 
    447 	return VFS_EXTATTRCTL(mp, cmd, vp, attrnamespace, attrname);
    448 }
    449 
    450 /*ARGSUSED*/
    451 void
    452 rump_vfs_syncwait(struct mount *mp)
    453 {
    454 	int n;
    455 
    456 	n = buf_syncwait();
    457 	if (n)
    458 		printf("syncwait: unsynced buffers: %d\n", n);
    459 }
    460 
    461 /*
    462  * Dump info about mount point.  No locking.
    463  */
    464 void
    465 rump_vfs_mount_print(const char *path, int full)
    466 {
    467 #ifdef DEBUGPRINT
    468 	struct vnode *mvp;
    469 	struct vnode *vp;
    470 	int error;
    471 
    472 	rumpuser_dprintf("\n==== dumping mountpoint at ``%s'' ====\n\n", path);
    473 	if ((error = namei_simple_user(path, NSM_FOLLOW_NOEMULROOT, &mvp))!=0) {
    474 		rumpuser_dprintf("==== lookup error %d ====\n\n", error);
    475 		return;
    476 	}
    477 	vfs_mount_print(mvp->v_mount, full, (void *)rumpuser_dprintf);
    478 	if (full) {
    479 		rumpuser_dprintf("\n== dumping vnodes ==\n\n");
    480 		TAILQ_FOREACH(vp, &mvp->v_mount->mnt_vnodelist, v_mntvnodes) {
    481 			vfs_vnode_print(vp, full, (void *)rumpuser_dprintf);
    482 		}
    483 	}
    484 	vrele(mvp);
    485 	rumpuser_dprintf("\n==== done ====\n\n");
    486 #else
    487 	rumpuser_dprintf("mount dump not supported without DEBUGPRINT\n");
    488 #endif
    489 }
    490 
    491 void
    492 rump_biodone(void *arg, size_t count, int error)
    493 {
    494 	struct buf *bp = arg;
    495 
    496 	bp->b_resid = bp->b_bcount - count;
    497 	KASSERT(bp->b_resid >= 0);
    498 	bp->b_error = error;
    499 
    500 	biodone(bp);
    501 }
    502 
    503 void
    504 rump_vfs_drainbufs(int npages)
    505 {
    506 
    507 	mutex_enter(&bufcache_lock);
    508 	buf_drain(npages);
    509 	mutex_exit(&bufcache_lock);
    510 }
    511