Home | History | Annotate | Line # | Download | only in rumpvfs
rumpfs.c revision 1.17
      1 /*	$NetBSD: rumpfs.c,v 1.17 2009/05/19 13:42:35 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/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.17 2009/05/19 13:42:35 pooka Exp $");
     32 
     33 #include <sys/param.h>
     34 #include <sys/mount.h>
     35 #include <sys/vnode.h>
     36 #include <sys/errno.h>
     37 #include <sys/kauth.h>
     38 #include <sys/lock.h>
     39 #include <sys/lockf.h>
     40 #include <sys/stat.h>
     41 #include <sys/namei.h>
     42 #include <sys/queue.h>
     43 #include <sys/filedesc.h>
     44 #include <sys/syscallargs.h>
     45 #include <sys/atomic.h>
     46 
     47 #include <miscfs/fifofs/fifo.h>
     48 #include <miscfs/specfs/specdev.h>
     49 #include <miscfs/genfs/genfs.h>
     50 
     51 #include <rump/rumpuser.h>
     52 
     53 #include "rump_private.h"
     54 #include "rump_vfs_private.h"
     55 
     56 static int rump_vop_lookup(void *);
     57 static int rump_vop_getattr(void *);
     58 static int rump_vop_mkdir(void *);
     59 static int rump_vop_inactive(void *);
     60 static int rump_vop_reclaim(void *);
     61 static int rump_vop_success(void *);
     62 
     63 int (**dead_vnodeop_p)(void *);
     64 const struct vnodeopv_entry_desc dead_vnodeop_entries[] = {
     65 	{ &vop_default_desc, vn_default_error },
     66 	{ NULL, NULL }
     67 };
     68 const struct vnodeopv_desc dead_vnodeop_opv_desc =
     69 	{ &dead_vnodeop_p, dead_vnodeop_entries };
     70 
     71 int (**fifo_vnodeop_p)(void *);
     72 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
     73 	{ &vop_default_desc, vn_default_error },
     74 	{ NULL, NULL }
     75 };
     76 const struct vnodeopv_desc fifo_vnodeop_opv_desc =
     77 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
     78 
     79 int (**rump_vnodeop_p)(void *);
     80 const struct vnodeopv_entry_desc rump_vnodeop_entries[] = {
     81 	{ &vop_default_desc, vn_default_error },
     82 	{ &vop_lookup_desc, rump_vop_lookup },
     83 	{ &vop_getattr_desc, rump_vop_getattr },
     84 	{ &vop_mkdir_desc, rump_vop_mkdir },
     85 	{ &vop_putpages_desc, genfs_null_putpages },
     86 	{ &vop_fsync_desc, rump_vop_success },
     87 	{ &vop_lock_desc, genfs_lock },
     88 	{ &vop_unlock_desc, genfs_unlock },
     89 	{ &vop_inactive_desc, rump_vop_inactive },
     90 	{ &vop_reclaim_desc, rump_vop_reclaim },
     91 	{ NULL, NULL }
     92 };
     93 const struct vnodeopv_desc rump_vnodeop_opv_desc =
     94 	{ &rump_vnodeop_p, rump_vnodeop_entries };
     95 const struct vnodeopv_desc * const rump_opv_descs[] = {
     96 	&rump_vnodeop_opv_desc,
     97 	NULL
     98 };
     99 
    100 static struct mount rump_mnt;
    101 static int lastino = 1;
    102 static kmutex_t reclock;
    103 
    104 struct rumpfs_dent {
    105 	char *rd_name;
    106 	struct rumpfs_node *rd_node;
    107 
    108 	LIST_ENTRY(rumpfs_dent) rd_entries;
    109 };
    110 
    111 struct rumpfs_node {
    112 	struct vattr rn_va;
    113 	struct vnode *rn_vp;
    114 
    115 	/* only for VDIR */
    116 	LIST_HEAD(, rumpfs_dent) rn_dir;
    117 };
    118 
    119 static struct rumpfs_node *
    120 makeprivate(enum vtype vt)
    121 {
    122 	struct rumpfs_node *rn;
    123 	struct vattr *va;
    124 	struct timespec ts;
    125 
    126 	rn = kmem_alloc(sizeof(*rn), KM_SLEEP);
    127 	LIST_INIT(&rn->rn_dir);
    128 	nanotime(&ts);
    129 
    130 	va = &rn->rn_va;
    131 	va->va_type = vt;
    132 	va->va_mode = 0755;
    133 	if (vt == VDIR)
    134 		va->va_nlink = 2;
    135 	else
    136 		va->va_nlink = 1;
    137 	va->va_uid = 0;
    138 	va->va_gid = 0;
    139 	va->va_fsid =
    140 	va->va_fileid = atomic_inc_uint_nv(&lastino);
    141 	va->va_size = 512;
    142 	va->va_blocksize = 512;
    143 	va->va_atime = ts;
    144 	va->va_mtime = ts;
    145 	va->va_ctime = ts;
    146 	va->va_birthtime = ts;
    147 	va->va_gen = 0;
    148 	va->va_flags = 0;
    149 	va->va_rdev = -1;
    150 	va->va_bytes = 512;
    151 	va->va_filerev = 0;
    152 	va->va_vaflags = 0;
    153 
    154 	return rn;
    155 }
    156 
    157 static int
    158 rump_makevnode(const char *path, size_t size, enum vtype vt, struct vnode **vpp)
    159 {
    160 	struct vnode *vp;
    161 	struct rumpfs_node *rn;
    162 	int (**vpops)(void *);
    163 	int rv;
    164 
    165 	if (vt == VREG || vt == VCHR || vt == VBLK) {
    166 		vt = VBLK;
    167 		vpops = spec_vnodeop_p;
    168 	} else {
    169 		vpops = rump_vnodeop_p;
    170 	}
    171 	if (vt != VBLK && vt != VDIR)
    172 		panic("rump_makevnode: only VBLK/VDIR vnodes supported");
    173 
    174 	rv = getnewvnode(VT_RUMP, &rump_mnt, vpops, &vp);
    175 	if (rv)
    176 		return rv;
    177 
    178 	vp->v_size = vp->v_writesize = size;
    179 	vp->v_type = vt;
    180 
    181 	if (vp->v_type == VBLK) {
    182 		rv = rumpblk_register(path);
    183 		if (rv == -1)
    184 			panic("rump_makevnode: lazy bum");
    185 		spec_node_init(vp, makedev(RUMPBLK, rv));
    186 	}
    187 	if (vt != VBLK) {
    188 		rn = makeprivate(vp->v_type);
    189 		rn->rn_vp = vp;
    190 		vp->v_data = rn;
    191 	}
    192 
    193 	vn_lock(vp, LK_RETRY | LK_EXCLUSIVE);
    194 	*vpp = vp;
    195 
    196 	return 0;
    197 }
    198 
    199 /*
    200  * Simple lookup for faking lookup of device entry for rump file systems
    201  * and for locating/creating directories.  Yes, this will panic if you
    202  * call it with the wrong arguments.
    203  */
    204 static int
    205 rump_vop_lookup(void *v)
    206 {
    207 	struct vop_lookup_args /* {
    208 		struct vnode *a_dvp;
    209 		struct vnode **a_vpp;
    210 		struct componentname *a_cnp;
    211 	}; */ *ap = v;
    212 	struct componentname *cnp = ap->a_cnp;
    213 	struct vnode *dvp = ap->a_dvp;
    214 	struct vnode **vpp = ap->a_vpp;
    215 	struct vnode *vp;
    216 	struct rumpfs_node *rn = dvp->v_data;
    217 	struct rumpfs_dent *rd;
    218 	uint64_t fsize;
    219 	enum vtype vt;
    220 	int rv, error, ft;
    221 
    222 	/* we handle only some "non-special" cases */
    223 	KASSERT(((cnp->cn_flags & ISLASTCN) == 0)
    224 	    || (cnp->cn_nameiop == LOOKUP || cnp->cn_nameiop == CREATE));
    225 	KASSERT((cnp->cn_flags & ISDOTDOT) == 0);
    226 	KASSERT(cnp->cn_namelen != 0 && cnp->cn_pnbuf[0] != '.');
    227 
    228 	/* check if we are returning a faked block device */
    229 	if (dvp == rootvnode && cnp->cn_nameiop == LOOKUP) {
    230 		if (rump_fakeblk_find(cnp->cn_pnbuf)) {
    231 			rv = rumpuser_getfileinfo(cnp->cn_pnbuf, &fsize,
    232 			    &ft, &error);
    233 			if (rv)
    234 				return rv;
    235 			switch (ft) {
    236 			case RUMPUSER_FT_DIR:
    237 				vt = VDIR;
    238 				break;
    239 			case RUMPUSER_FT_REG:
    240 				vt = VREG;
    241 				break;
    242 			case RUMPUSER_FT_BLK:
    243 				vt = VBLK;
    244 				break;
    245 			case RUMPUSER_FT_CHR:
    246 				vt = VCHR;
    247 				break;
    248 			default:
    249 				vt = VBAD;
    250 				break;
    251 			}
    252 			error = rump_makevnode(cnp->cn_pnbuf, fsize, vt, vpp);
    253 			if (error)
    254 				return error;
    255 			cnp->cn_consume = strlen(cnp->cn_nameptr
    256 			    + cnp->cn_namelen);
    257 			cnp->cn_flags &= ~REQUIREDIR;
    258 
    259 			return 0;
    260 		}
    261 	}
    262 
    263 	LIST_FOREACH(rd, &rn->rn_dir, rd_entries) {
    264 		if (strncmp(rd->rd_name, cnp->cn_nameptr,
    265 		    cnp->cn_namelen) == 0)
    266 			break;
    267 	}
    268 
    269 	if (!rd && ((cnp->cn_flags & ISLASTCN) == 0||cnp->cn_nameiop != CREATE))
    270 		return ENOENT;
    271 
    272 	if (!rd && (cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
    273 		cnp->cn_flags |= SAVENAME;
    274 		return EJUSTRETURN;
    275 	}
    276 	KASSERT(rd);
    277 	KASSERT(rd->rd_node->rn_va.va_type == VDIR);
    278 
    279  retry:
    280 	mutex_enter(&reclock);
    281 	if ((vp = rd->rd_node->rn_vp)) {
    282 		mutex_enter(&vp->v_interlock);
    283 		mutex_exit(&reclock);
    284 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
    285 			goto retry;
    286 		*vpp = vp;
    287 	} else {
    288 		rv = rump_makevnode(cnp->cn_nameptr, DEV_BSIZE, VDIR, vpp);
    289 		if (rv)
    290 			return rv;
    291 	}
    292 
    293 	return 0;
    294 }
    295 
    296 static int
    297 rump_vop_getattr(void *v)
    298 {
    299 	struct vop_getattr_args /* {
    300 		struct vnode *a_vp;
    301 		struct vattr *a_vap;
    302 		kauth_cred_t a_cred;
    303 	} */ *ap = v;
    304 	struct rumpfs_node *rn = ap->a_vp->v_data;
    305 
    306 	memcpy(ap->a_vap, &rn->rn_va, sizeof(struct vattr));
    307 	return 0;
    308 }
    309 
    310 static int
    311 rump_vop_mkdir(void *v)
    312 {
    313 	struct vop_mkdir_args /* {
    314 		struct vnode *a_dvp;
    315 		struct vnode **a_vpp;
    316 		struct componentname *a_cnp;
    317 		struct vattr *a_vap;
    318 	}; */ *ap = v;
    319 	struct vnode *dvp = ap->a_dvp;
    320 	struct vnode **vpp = ap->a_vpp;
    321 	struct componentname *cnp = ap->a_cnp;
    322 	struct rumpfs_node *rnd = dvp->v_data;
    323 	struct rumpfs_dent *rdent;
    324 	int rv = 0;
    325 
    326 	if ((rv = rump_makevnode(cnp->cn_nameptr, DEV_BSIZE, VDIR, vpp)) != 0)
    327 		goto out;
    328 
    329 	rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP);
    330 	rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP);
    331 	rdent->rd_node = (*vpp)->v_data;
    332 	strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1);
    333 
    334 	LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries);
    335 
    336  out:
    337 	vput(dvp);
    338 	return rv;
    339 }
    340 
    341 static int
    342 rump_vop_success(void *v)
    343 {
    344 
    345 	return 0;
    346 }
    347 
    348 static int
    349 rump_vop_inactive(void *v)
    350 {
    351 	struct vop_inactive_args *ap = v;
    352 
    353 	VOP_UNLOCK(ap->a_vp, 0);
    354 	return 0;
    355 }
    356 
    357 static int
    358 rump_vop_reclaim(void *v)
    359 {
    360 	struct vop_reclaim_args /* {
    361 		struct vnode *a_vp;
    362 	} */ *ap = v;
    363 	struct vnode *vp = ap->a_vp;
    364 	struct rumpfs_node *rn = vp->v_data;
    365 
    366 	mutex_enter(&reclock);
    367 	rn->rn_vp = NULL;
    368 	mutex_exit(&reclock);
    369 	vp->v_data = NULL;
    370 
    371 	return 0;
    372 }
    373 
    374 void
    375 rumpfs_init(void)
    376 {
    377 	int rv;
    378 
    379 	mutex_init(&reclock, MUTEX_DEFAULT, IPL_NONE);
    380 
    381 	/* XXX: init properly instead of this crap */
    382 	rump_mnt.mnt_refcnt = 1;
    383 	rump_mnt.mnt_flag = MNT_ROOTFS;
    384 	rw_init(&rump_mnt.mnt_unmounting);
    385 	TAILQ_INIT(&rump_mnt.mnt_vnodelist);
    386 
    387 	vfs_opv_init(rump_opv_descs);
    388 	rv = rump_makevnode("/", 0, VDIR, &rootvnode);
    389 	if (rv)
    390 		panic("could not create root vnode: %d", rv);
    391 	rootvnode->v_vflag |= VV_ROOT;
    392 	VOP_UNLOCK(rootvnode, 0);
    393 }
    394