Home | History | Annotate | Line # | Download | only in puffs
puffs_subr.c revision 1.22.2.12
      1  1.22.2.12     ad /*	$NetBSD: puffs_subr.c,v 1.22.2.12 2007/10/09 13:44:19 ad Exp $	*/
      2        1.1  pooka 
      3        1.1  pooka /*
      4  1.22.2.12     ad  * Copyright (c) 2006, 2007  Antti Kantee.  All Rights Reserved.
      5        1.1  pooka  *
      6        1.1  pooka  * Development of this software was supported by the
      7  1.22.2.12     ad  * Ulla Tuominen Foundation and the Finnish Cultural Foundation.
      8        1.1  pooka  *
      9        1.1  pooka  * Redistribution and use in source and binary forms, with or without
     10        1.1  pooka  * modification, are permitted provided that the following conditions
     11        1.1  pooka  * are met:
     12        1.1  pooka  * 1. Redistributions of source code must retain the above copyright
     13        1.1  pooka  *    notice, this list of conditions and the following disclaimer.
     14        1.1  pooka  * 2. Redistributions in binary form must reproduce the above copyright
     15        1.1  pooka  *    notice, this list of conditions and the following disclaimer in the
     16        1.1  pooka  *    documentation and/or other materials provided with the distribution.
     17        1.1  pooka  *
     18        1.1  pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     19        1.1  pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20        1.1  pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21        1.1  pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22        1.1  pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23        1.1  pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     24        1.1  pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25        1.1  pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26        1.1  pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27        1.1  pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28        1.1  pooka  * SUCH DAMAGE.
     29        1.1  pooka  */
     30        1.1  pooka 
     31        1.1  pooka #include <sys/cdefs.h>
     32  1.22.2.12     ad __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.22.2.12 2007/10/09 13:44:19 ad Exp $");
     33        1.1  pooka 
     34        1.1  pooka #include <sys/param.h>
     35        1.1  pooka #include <sys/conf.h>
     36       1.16  pooka #include <sys/hash.h>
     37   1.22.2.5     ad #include <sys/kauth.h>
     38        1.1  pooka #include <sys/malloc.h>
     39        1.1  pooka #include <sys/mount.h>
     40   1.22.2.5     ad #include <sys/namei.h>
     41   1.22.2.5     ad #include <sys/poll.h>
     42        1.1  pooka #include <sys/socketvar.h>
     43        1.1  pooka #include <sys/vnode.h>
     44   1.22.2.3     ad #include <sys/proc.h>
     45        1.1  pooka 
     46        1.1  pooka #include <fs/puffs/puffs_msgif.h>
     47        1.1  pooka #include <fs/puffs/puffs_sys.h>
     48        1.1  pooka 
     49        1.7  pooka #include <miscfs/genfs/genfs_node.h>
     50        1.4  pooka #include <miscfs/specfs/specdev.h>
     51        1.4  pooka 
     52   1.22.2.4     ad struct pool puffs_pnpool;
     53        1.1  pooka 
     54       1.19  pooka #ifdef PUFFSDEBUG
     55       1.10  pooka int puffsdebug;
     56       1.10  pooka #endif
     57       1.10  pooka 
     58       1.16  pooka static __inline struct puffs_node_hashlist
     59       1.16  pooka 	*puffs_cookie2hashlist(struct puffs_mount *, void *);
     60       1.16  pooka static struct puffs_node *puffs_cookie2pnode(struct puffs_mount *, void *);
     61        1.7  pooka 
     62        1.7  pooka static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
     63        1.7  pooka static void puffs_gop_markupdate(struct vnode *, int);
     64        1.7  pooka 
     65        1.7  pooka static const struct genfs_ops puffs_genfsops = {
     66        1.7  pooka 	.gop_size = puffs_gop_size,
     67        1.7  pooka 	.gop_write = genfs_gop_write,
     68        1.7  pooka 	.gop_markupdate = puffs_gop_markupdate,
     69        1.7  pooka #if 0
     70        1.7  pooka 	.gop_alloc, should ask userspace
     71        1.7  pooka #endif
     72        1.7  pooka };
     73        1.7  pooka 
     74        1.1  pooka /*
     75        1.1  pooka  * Grab a vnode, intialize all the puffs-dependant stuff.
     76        1.1  pooka  */
     77        1.1  pooka int
     78        1.4  pooka puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
     79        1.7  pooka 	voff_t vsize, dev_t rdev, struct vnode **vpp)
     80        1.1  pooka {
     81        1.1  pooka 	struct puffs_mount *pmp;
     82        1.4  pooka 	struct vnode *vp, *nvp;
     83        1.1  pooka 	struct puffs_node *pnode;
     84       1.16  pooka 	struct puffs_node_hashlist *plist;
     85        1.1  pooka 	int error;
     86        1.1  pooka 
     87   1.22.2.8     ad 	if (type <= VNON || type >= VBAD)
     88   1.22.2.8     ad 		return EINVAL;
     89   1.22.2.8     ad 
     90        1.1  pooka 	pmp = MPTOPUFFSMP(mp);
     91        1.1  pooka 
     92        1.2  pooka 	/*
     93        1.2  pooka 	 * XXX: there is a deadlock condition between vfs_busy() and
     94        1.2  pooka 	 * vnode locks.  For an unmounting file system the mountpoint
     95        1.2  pooka 	 * is frozen, but in unmount(FORCE) vflush() wants to access all
     96        1.2  pooka 	 * of the vnodes.  If we are here waiting for the mountpoint
     97        1.2  pooka 	 * lock while holding on to a vnode lock, well, we ain't
     98        1.2  pooka 	 * just pining for the fjords anymore.  If we release the
     99        1.2  pooka 	 * vnode lock, we will be in the situation "mount point
    100        1.2  pooka 	 * is dying" and panic() will ensue in insmntque.  So as a
    101        1.2  pooka 	 * temporary workaround, get a vnode without putting it on
    102        1.2  pooka 	 * the mount point list, check if mount point is still alive
    103        1.2  pooka 	 * and kicking and only then add the vnode to the list.
    104        1.2  pooka 	 */
    105        1.2  pooka 	error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
    106        1.2  pooka 	if (error)
    107        1.1  pooka 		return error;
    108        1.2  pooka 	vp->v_vnlock = NULL;
    109        1.4  pooka 	vp->v_type = type;
    110        1.2  pooka 
    111        1.2  pooka 	/*
    112        1.2  pooka 	 * Check what mount point isn't going away.  This will work
    113        1.2  pooka 	 * until we decide to remove biglock or make the kernel
    114        1.2  pooka 	 * preemptive.  But hopefully the real problem will be fixed
    115        1.2  pooka 	 * by then.
    116        1.2  pooka 	 *
    117        1.2  pooka 	 * XXX: yes, should call vfs_busy(), but thar be rabbits with
    118        1.2  pooka 	 * vicious streaks a mile wide ...
    119        1.2  pooka 	 */
    120        1.2  pooka 	if (mp->mnt_iflag & IMNT_UNMOUNT) {
    121        1.2  pooka 		DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
    122        1.2  pooka 		    "vnode for cookie %p\n", mp, cookie));
    123        1.2  pooka 		ungetnewvnode(vp);
    124        1.2  pooka 		return ENXIO;
    125        1.1  pooka 	}
    126        1.1  pooka 
    127        1.2  pooka 	/* So it's not dead yet.. good.. inform new vnode of its master */
    128   1.22.2.2     ad 	mutex_enter(&mntvnode_lock);
    129       1.16  pooka 	TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
    130   1.22.2.2     ad 	mutex_exit(&mntvnode_lock);
    131        1.2  pooka 	vp->v_mount = mp;
    132        1.2  pooka 
    133        1.4  pooka 	/*
    134        1.4  pooka 	 * clerical tasks & footwork
    135        1.4  pooka 	 */
    136        1.4  pooka 
    137   1.22.2.5     ad 	/* default size */
    138   1.22.2.5     ad 	uvm_vnp_setsize(vp, 0);
    139   1.22.2.5     ad 
    140        1.4  pooka 	/* dances based on vnode type. almost ufs_vinit(), but not quite */
    141        1.4  pooka 	switch (type) {
    142        1.4  pooka 	case VCHR:
    143        1.4  pooka 	case VBLK:
    144        1.4  pooka 		/*
    145        1.4  pooka 		 * replace vnode operation vector with the specops vector.
    146        1.4  pooka 		 * our user server has very little control over the node
    147        1.4  pooka 		 * if it decides its a character or block special file
    148        1.4  pooka 		 */
    149        1.4  pooka 		vp->v_op = puffs_specop_p;
    150        1.4  pooka 
    151        1.4  pooka 		/* do the standard checkalias-dance */
    152        1.4  pooka 		if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
    153        1.4  pooka 			/*
    154        1.6  pooka 			 * found: release & unallocate aliased
    155        1.4  pooka 			 * old (well, actually, new) node
    156        1.4  pooka 			 */
    157        1.4  pooka 			vp->v_op = spec_vnodeop_p;
    158   1.22.2.7     ad 			mutex_enter(&vp->v_interlock);
    159   1.22.2.7     ad 			vp->v_iflag &= ~VI_LOCKSWORK;
    160   1.22.2.7     ad 			mutex_exit(&vp->v_interlock);
    161        1.4  pooka 			vgone(vp); /* cya */
    162        1.4  pooka 
    163        1.4  pooka 			/* init "new" vnode */
    164        1.4  pooka 			vp = nvp;
    165        1.4  pooka 			vp->v_vnlock = NULL;
    166        1.4  pooka 			vp->v_mount = mp;
    167        1.4  pooka 		}
    168        1.4  pooka 		break;
    169        1.7  pooka 
    170        1.5  pooka 	case VFIFO:
    171        1.5  pooka 		vp->v_op = puffs_fifoop_p;
    172        1.5  pooka 		break;
    173        1.7  pooka 
    174        1.7  pooka 	case VREG:
    175        1.7  pooka 		uvm_vnp_setsize(vp, vsize);
    176        1.7  pooka 		break;
    177        1.7  pooka 
    178        1.5  pooka 	case VDIR:
    179        1.5  pooka 	case VLNK:
    180        1.5  pooka 	case VSOCK:
    181        1.5  pooka 		break;
    182        1.4  pooka 	default:
    183        1.5  pooka #ifdef DIAGNOSTIC
    184        1.5  pooka 		panic("puffs_getvnode: invalid vtype %d", type);
    185        1.5  pooka #endif
    186        1.4  pooka 		break;
    187        1.4  pooka 	}
    188        1.4  pooka 
    189        1.2  pooka 	pnode = pool_get(&puffs_pnpool, PR_WAITOK);
    190  1.22.2.10     ad 	memset(pnode, 0, sizeof(struct puffs_node));
    191  1.22.2.10     ad 
    192        1.1  pooka 	pnode->pn_cookie = cookie;
    193   1.22.2.5     ad 	pnode->pn_refcount = 1;
    194   1.22.2.5     ad 
    195   1.22.2.5     ad 	mutex_init(&pnode->pn_mtx, MUTEX_DEFAULT, IPL_NONE);
    196   1.22.2.5     ad 	SLIST_INIT(&pnode->pn_sel.sel_klist);
    197   1.22.2.5     ad 
    198       1.16  pooka 	plist = puffs_cookie2hashlist(pmp, cookie);
    199       1.16  pooka 	LIST_INSERT_HEAD(plist, pnode, pn_hashent);
    200        1.1  pooka 	vp->v_data = pnode;
    201        1.4  pooka 	vp->v_type = type;
    202        1.1  pooka 	pnode->pn_vp = vp;
    203  1.22.2.10     ad 	pnode->pn_serversize = vsize;
    204        1.1  pooka 
    205        1.7  pooka 	genfs_node_init(vp, &puffs_genfsops);
    206        1.1  pooka 	*vpp = vp;
    207        1.1  pooka 
    208        1.1  pooka 	DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
    209        1.1  pooka 	    pnode, pnode->pn_cookie));
    210        1.1  pooka 
    211        1.1  pooka 	return 0;
    212        1.1  pooka }
    213        1.1  pooka 
    214        1.1  pooka /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
    215        1.1  pooka int
    216        1.1  pooka puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
    217        1.4  pooka 	void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
    218        1.1  pooka {
    219       1.13  pooka 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
    220        1.1  pooka 	struct vnode *vp;
    221        1.1  pooka 	int error;
    222        1.1  pooka 
    223        1.1  pooka 	/* userspace probably has this as a NULL op */
    224        1.1  pooka 	if (cookie == NULL) {
    225        1.1  pooka 		error = EOPNOTSUPP;
    226        1.3  pooka 		return error;
    227        1.1  pooka 	}
    228        1.1  pooka 
    229       1.15  pooka 	/*
    230       1.15  pooka 	 * Check for previous node with the same designation.
    231       1.20  pooka 	 * Explicitly check the root node cookie, since it might be
    232       1.20  pooka 	 * reclaimed from the kernel when this check is made.
    233       1.15  pooka 	 *
    234       1.15  pooka 	 * XXX: technically this error check should punish the fs,
    235       1.15  pooka 	 * not the caller.
    236       1.15  pooka 	 */
    237   1.22.2.4     ad 	mutex_enter(&pmp->pmp_lock);
    238   1.22.2.5     ad 	if (cookie == pmp->pmp_root_cookie
    239       1.20  pooka 	    || puffs_cookie2pnode(pmp, cookie) != NULL) {
    240   1.22.2.4     ad 		mutex_exit(&pmp->pmp_lock);
    241       1.15  pooka 		error = EEXIST;
    242       1.15  pooka 		return error;
    243       1.15  pooka 	}
    244   1.22.2.4     ad 	mutex_exit(&pmp->pmp_lock);
    245       1.15  pooka 
    246        1.7  pooka 	error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
    247        1.1  pooka 	if (error)
    248        1.3  pooka 		return error;
    249        1.1  pooka 
    250        1.1  pooka 	vp->v_type = type;
    251        1.1  pooka 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    252        1.1  pooka 	*vpp = vp;
    253        1.1  pooka 
    254   1.22.2.8     ad 	if ((cnp->cn_flags & MAKEENTRY) && PUFFS_USE_NAMECACHE(pmp))
    255       1.13  pooka 		cache_enter(dvp, vp, cnp);
    256       1.13  pooka 
    257        1.3  pooka 	return 0;
    258        1.1  pooka }
    259        1.1  pooka 
    260   1.22.2.5     ad /*
    261   1.22.2.5     ad  * Release pnode structure which dealing with references to the
    262   1.22.2.5     ad  * puffs_node instead of the vnode.  Can't use vref()/vrele() on
    263   1.22.2.5     ad  * the vnode there, since that causes the lovely VOP_INACTIVE(),
    264   1.22.2.5     ad  * which in turn causes the lovely deadlock when called by the one
    265   1.22.2.5     ad  * who is supposed to handle it.
    266   1.22.2.5     ad  */
    267   1.22.2.5     ad void
    268   1.22.2.5     ad puffs_releasenode(struct puffs_node *pn)
    269   1.22.2.5     ad {
    270   1.22.2.5     ad 
    271   1.22.2.5     ad 	mutex_enter(&pn->pn_mtx);
    272   1.22.2.5     ad 	if (--pn->pn_refcount == 0) {
    273   1.22.2.5     ad 		mutex_exit(&pn->pn_mtx);
    274   1.22.2.5     ad 		mutex_destroy(&pn->pn_mtx);
    275   1.22.2.5     ad 		pool_put(&puffs_pnpool, pn);
    276   1.22.2.5     ad 	} else {
    277   1.22.2.5     ad 		mutex_exit(&pn->pn_mtx);
    278   1.22.2.5     ad 	}
    279   1.22.2.5     ad }
    280   1.22.2.5     ad 
    281   1.22.2.5     ad /*
    282   1.22.2.5     ad  * Add reference to node.
    283   1.22.2.5     ad  *  mutex held on entry and return
    284   1.22.2.5     ad  */
    285   1.22.2.5     ad void
    286   1.22.2.5     ad puffs_referencenode(struct puffs_node *pn)
    287   1.22.2.5     ad {
    288   1.22.2.5     ad 
    289   1.22.2.5     ad 	KASSERT(mutex_owned(&pn->pn_mtx));
    290   1.22.2.5     ad 	pn->pn_refcount++;
    291   1.22.2.5     ad }
    292   1.22.2.5     ad 
    293        1.1  pooka void
    294        1.1  pooka puffs_putvnode(struct vnode *vp)
    295        1.1  pooka {
    296        1.1  pooka 	struct puffs_mount *pmp;
    297        1.1  pooka 	struct puffs_node *pnode;
    298        1.1  pooka 
    299        1.1  pooka 	pmp = VPTOPUFFSMP(vp);
    300        1.1  pooka 	pnode = VPTOPP(vp);
    301        1.1  pooka 
    302        1.1  pooka #ifdef DIAGNOSTIC
    303        1.1  pooka 	if (vp->v_tag != VT_PUFFS)
    304        1.1  pooka 		panic("puffs_putvnode: %p not a puffs vnode", vp);
    305        1.1  pooka #endif
    306        1.1  pooka 
    307       1.16  pooka 	LIST_REMOVE(pnode, pn_hashent);
    308       1.21     ad 	genfs_node_destroy(vp);
    309   1.22.2.5     ad 	puffs_releasenode(pnode);
    310        1.1  pooka 	vp->v_data = NULL;
    311        1.1  pooka 
    312        1.1  pooka 	return;
    313        1.1  pooka }
    314        1.1  pooka 
    315       1.16  pooka static __inline struct puffs_node_hashlist *
    316       1.16  pooka puffs_cookie2hashlist(struct puffs_mount *pmp, void *cookie)
    317       1.16  pooka {
    318       1.16  pooka 	uint32_t hash;
    319       1.16  pooka 
    320       1.16  pooka 	hash = hash32_buf(&cookie, sizeof(void *), HASH32_BUF_INIT);
    321       1.16  pooka 	return &pmp->pmp_pnodehash[hash % pmp->pmp_npnodehash];
    322       1.16  pooka }
    323       1.16  pooka 
    324        1.1  pooka /*
    325       1.15  pooka  * Translate cookie to puffs_node.  Caller must hold mountpoint
    326       1.15  pooka  * lock and it will be held upon return.
    327       1.15  pooka  */
    328       1.16  pooka static struct puffs_node *
    329       1.15  pooka puffs_cookie2pnode(struct puffs_mount *pmp, void *cookie)
    330       1.15  pooka {
    331       1.16  pooka 	struct puffs_node_hashlist *plist;
    332       1.15  pooka 	struct puffs_node *pnode;
    333       1.15  pooka 
    334       1.16  pooka 	plist = puffs_cookie2hashlist(pmp, cookie);
    335       1.16  pooka 	LIST_FOREACH(pnode, plist, pn_hashent) {
    336       1.15  pooka 		if (pnode->pn_cookie == cookie)
    337       1.15  pooka 			break;
    338       1.15  pooka 	}
    339       1.15  pooka 
    340       1.15  pooka 	return pnode;
    341       1.15  pooka }
    342       1.15  pooka 
    343       1.15  pooka /*
    344   1.22.2.8     ad  * Make sure root vnode exists and reference it.  Does NOT lock.
    345   1.22.2.8     ad  */
    346   1.22.2.8     ad static int
    347   1.22.2.8     ad puffs_makeroot(struct puffs_mount *pmp)
    348   1.22.2.8     ad {
    349   1.22.2.8     ad 	struct vnode *vp;
    350   1.22.2.8     ad 	int rv;
    351   1.22.2.8     ad 
    352   1.22.2.8     ad 	/*
    353   1.22.2.8     ad 	 * pmp_lock must be held if vref()'ing or vrele()'ing the
    354   1.22.2.8     ad 	 * root vnode.  the latter is controlled by puffs_inactive().
    355   1.22.2.8     ad 	 *
    356   1.22.2.8     ad 	 * pmp_root is set here and cleared in puffs_reclaim().
    357   1.22.2.8     ad 	 */
    358   1.22.2.8     ad  retry:
    359   1.22.2.8     ad 	mutex_enter(&pmp->pmp_lock);
    360   1.22.2.8     ad 	vp = pmp->pmp_root;
    361   1.22.2.8     ad 	if (vp) {
    362   1.22.2.8     ad 		mutex_enter(&vp->v_interlock);
    363   1.22.2.8     ad 		mutex_exit(&pmp->pmp_lock);
    364   1.22.2.8     ad 		if (vget(vp, LK_INTERLOCK) == 0)
    365   1.22.2.8     ad 			return 0;
    366   1.22.2.8     ad 	} else
    367   1.22.2.8     ad 		mutex_exit(&pmp->pmp_lock);
    368   1.22.2.8     ad 
    369   1.22.2.8     ad 	/*
    370   1.22.2.8     ad 	 * So, didn't have the magic root vnode available.
    371   1.22.2.8     ad 	 * No matter, grab another an stuff it with the cookie.
    372   1.22.2.8     ad 	 */
    373   1.22.2.8     ad 	if ((rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie,
    374   1.22.2.8     ad 	    pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp)))
    375   1.22.2.8     ad 		return rv;
    376   1.22.2.8     ad 
    377   1.22.2.8     ad 	/*
    378   1.22.2.8     ad 	 * Someone magically managed to race us into puffs_getvnode?
    379   1.22.2.8     ad 	 * Put our previous new vnode back and retry.
    380   1.22.2.8     ad 	 */
    381   1.22.2.8     ad 	mutex_enter(&pmp->pmp_lock);
    382   1.22.2.8     ad 	if (pmp->pmp_root) {
    383   1.22.2.8     ad 		mutex_exit(&pmp->pmp_lock);
    384   1.22.2.8     ad 		puffs_putvnode(vp);
    385   1.22.2.8     ad 		goto retry;
    386   1.22.2.8     ad 	}
    387   1.22.2.8     ad 
    388   1.22.2.8     ad 	/* store cache */
    389   1.22.2.8     ad 	vp->v_vflag = VV_ROOT;
    390   1.22.2.8     ad 	pmp->pmp_root = vp;
    391   1.22.2.8     ad 	mutex_exit(&pmp->pmp_lock);
    392   1.22.2.8     ad 
    393   1.22.2.8     ad 	return 0;
    394   1.22.2.8     ad }
    395   1.22.2.8     ad 
    396   1.22.2.8     ad /*
    397        1.1  pooka  * Locate the in-kernel vnode based on the cookie received given
    398       1.20  pooka  * from userspace.  Returns a vnode, if found, NULL otherwise.
    399       1.20  pooka  * The parameter "lock" control whether to lock the possible or
    400       1.20  pooka  * not.  Locking always might cause us to lock against ourselves
    401       1.20  pooka  * in situations where we want the vnode but don't care for the
    402       1.20  pooka  * vnode lock, e.g. file server issued putpages.
    403        1.1  pooka  */
    404   1.22.2.8     ad int
    405   1.22.2.8     ad puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie, int lock,
    406   1.22.2.8     ad 	struct vnode **vpp)
    407        1.1  pooka {
    408        1.1  pooka 	struct puffs_node *pnode;
    409        1.1  pooka 	struct vnode *vp;
    410   1.22.2.8     ad 	int vgetflags, rv;
    411        1.1  pooka 
    412       1.20  pooka 	/*
    413   1.22.2.8     ad 	 * Handle root in a special manner, since we want to make sure
    414   1.22.2.8     ad 	 * pmp_root is properly set.
    415       1.20  pooka 	 */
    416   1.22.2.5     ad 	if (cookie == pmp->pmp_root_cookie) {
    417   1.22.2.8     ad 		if ((rv = puffs_makeroot(pmp)))
    418   1.22.2.8     ad 			return rv;
    419   1.22.2.8     ad 		if (lock)
    420   1.22.2.8     ad 			vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
    421       1.20  pooka 
    422   1.22.2.8     ad 		*vpp = pmp->pmp_root;
    423   1.22.2.8     ad 		return 0;
    424       1.20  pooka 	}
    425       1.20  pooka 
    426   1.22.2.4     ad 	mutex_enter(&pmp->pmp_lock);
    427       1.15  pooka 	pnode = puffs_cookie2pnode(pmp, cookie);
    428       1.14  pooka 
    429       1.15  pooka 	if (pnode == NULL) {
    430   1.22.2.4     ad 		mutex_exit(&pmp->pmp_lock);
    431   1.22.2.8     ad 		return ENOENT;
    432       1.15  pooka 	}
    433       1.17  pooka 
    434   1.22.2.8     ad 	vp = pnode->pn_vp;
    435   1.22.2.3     ad 	mutex_enter(&vp->v_interlock);
    436   1.22.2.4     ad 	mutex_exit(&pmp->pmp_lock);
    437        1.1  pooka 
    438   1.22.2.8     ad 	vgetflags = LK_INTERLOCK;
    439   1.22.2.8     ad 	if (lock)
    440   1.22.2.8     ad 		vgetflags |= LK_EXCLUSIVE | LK_RETRY;
    441   1.22.2.8     ad 	if ((rv = vget(vp, vgetflags)))
    442   1.22.2.8     ad 		return rv;
    443       1.14  pooka 
    444   1.22.2.8     ad 	*vpp = vp;
    445   1.22.2.8     ad 	return 0;
    446        1.1  pooka }
    447        1.1  pooka 
    448        1.1  pooka void
    449   1.22.2.8     ad puffs_makecn(struct puffs_kcn *pkcn, struct puffs_kcred *pkcr,
    450   1.22.2.8     ad 	struct puffs_kcid *pkcid, const struct componentname *cn, int full)
    451        1.1  pooka {
    452        1.1  pooka 
    453       1.12  pooka 	pkcn->pkcn_nameiop = cn->cn_nameiop;
    454       1.12  pooka 	pkcn->pkcn_flags = cn->cn_flags;
    455   1.22.2.8     ad 	puffs_cidcvt(pkcid, cn->cn_lwp);
    456        1.1  pooka 
    457   1.22.2.8     ad 	if (full) {
    458   1.22.2.8     ad 		(void)strcpy(pkcn->pkcn_name, cn->cn_nameptr);
    459   1.22.2.8     ad 	} else {
    460   1.22.2.8     ad 		(void)memcpy(pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
    461   1.22.2.8     ad 		pkcn->pkcn_name[cn->cn_namelen] = '\0';
    462   1.22.2.8     ad 	}
    463       1.12  pooka 	pkcn->pkcn_namelen = cn->cn_namelen;
    464   1.22.2.8     ad 	pkcn->pkcn_consume = 0;
    465   1.22.2.8     ad 
    466   1.22.2.8     ad 	puffs_credcvt(pkcr, cn->cn_cred);
    467        1.1  pooka }
    468        1.1  pooka 
    469        1.1  pooka /*
    470   1.22.2.8     ad  * Convert given credentials to struct puffs_kcred for userspace.
    471        1.1  pooka  */
    472        1.1  pooka void
    473   1.22.2.8     ad puffs_credcvt(struct puffs_kcred *pkcr, const kauth_cred_t cred)
    474        1.1  pooka {
    475        1.1  pooka 
    476   1.22.2.8     ad 	memset(pkcr, 0, sizeof(struct puffs_kcred));
    477        1.1  pooka 
    478        1.1  pooka 	if (cred == NOCRED || cred == FSCRED) {
    479   1.22.2.8     ad 		pkcr->pkcr_type = PUFFCRED_TYPE_INTERNAL;
    480        1.1  pooka 		if (cred == NOCRED)
    481   1.22.2.8     ad 			pkcr->pkcr_internal = PUFFCRED_CRED_NOCRED;
    482        1.1  pooka 		if (cred == FSCRED)
    483   1.22.2.8     ad 			pkcr->pkcr_internal = PUFFCRED_CRED_FSCRED;
    484        1.1  pooka  	} else {
    485   1.22.2.8     ad 		pkcr->pkcr_type = PUFFCRED_TYPE_UUC;
    486   1.22.2.8     ad 		kauth_cred_to_uucred(&pkcr->pkcr_uuc, cred);
    487        1.1  pooka 	}
    488        1.1  pooka }
    489        1.1  pooka 
    490   1.22.2.8     ad void
    491   1.22.2.8     ad puffs_cidcvt(struct puffs_kcid *pkcid, const struct lwp *l)
    492        1.1  pooka {
    493        1.1  pooka 
    494   1.22.2.8     ad 	if (l) {
    495   1.22.2.8     ad 		pkcid->pkcid_type = PUFFCID_TYPE_REAL;
    496   1.22.2.8     ad 		pkcid->pkcid_pid = l->l_proc->p_pid;
    497   1.22.2.8     ad 		pkcid->pkcid_lwpid = l->l_lid;
    498   1.22.2.8     ad 	} else {
    499   1.22.2.8     ad 		pkcid->pkcid_type = PUFFCID_TYPE_FAKE;
    500   1.22.2.8     ad 		pkcid->pkcid_pid = 0;
    501   1.22.2.8     ad 		pkcid->pkcid_lwpid = 0;
    502   1.22.2.8     ad 	}
    503        1.1  pooka }
    504        1.7  pooka 
    505       1.11  pooka void
    506  1.22.2.12     ad puffs_parkdone_asyncbioread(struct puffs_mount *pmp,
    507  1.22.2.12     ad 	struct puffs_req *preq, void *arg)
    508       1.11  pooka {
    509   1.22.2.4     ad 	struct puffs_vnreq_read *read_argp = (void *)preq;
    510   1.22.2.4     ad 	struct buf *bp = arg;
    511   1.22.2.4     ad 	size_t moved;
    512   1.22.2.4     ad 
    513  1.22.2.12     ad 	bp->b_error = checkerr(pmp, preq->preq_rv, __func__);
    514   1.22.2.9     ad 	if (bp->b_error == 0) {
    515   1.22.2.4     ad 		moved = bp->b_bcount - read_argp->pvnr_resid;
    516   1.22.2.9     ad 		bp->b_resid = read_argp->pvnr_resid;
    517   1.22.2.9     ad 
    518   1.22.2.4     ad 		memcpy(bp->b_data, read_argp->pvnr_data, moved);
    519   1.22.2.9     ad 	}
    520       1.22  pooka 
    521   1.22.2.9     ad 	biodone(bp);
    522   1.22.2.4     ad 	free(preq, M_PUFFS);
    523       1.22  pooka }
    524   1.22.2.5     ad 
    525  1.22.2.10     ad /* XXX: userspace can leak kernel resources */
    526   1.22.2.5     ad void
    527  1.22.2.12     ad puffs_parkdone_poll(struct puffs_mount *pmp, struct puffs_req *preq, void *arg)
    528   1.22.2.5     ad {
    529   1.22.2.5     ad 	struct puffs_vnreq_poll *poll_argp = (void *)preq;
    530   1.22.2.5     ad 	struct puffs_node *pn = arg;
    531  1.22.2.12     ad 	int revents, error;
    532   1.22.2.5     ad 
    533  1.22.2.12     ad 	error = checkerr(pmp, preq->preq_rv, __func__);
    534  1.22.2.12     ad 	if (error)
    535   1.22.2.5     ad 		revents = poll_argp->pvnr_events;
    536   1.22.2.5     ad 	else
    537   1.22.2.5     ad 		revents = POLLERR;
    538   1.22.2.5     ad 
    539   1.22.2.5     ad 	mutex_enter(&pn->pn_mtx);
    540   1.22.2.5     ad 	pn->pn_revents |= revents;
    541   1.22.2.5     ad 	mutex_exit(&pn->pn_mtx);
    542   1.22.2.5     ad 
    543   1.22.2.5     ad 	selnotify(&pn->pn_sel, 0);
    544   1.22.2.5     ad 	free(preq, M_PUFFS);
    545   1.22.2.5     ad 
    546   1.22.2.5     ad 	puffs_releasenode(pn);
    547   1.22.2.5     ad }
    548   1.22.2.5     ad 
    549   1.22.2.5     ad void
    550   1.22.2.5     ad puffs_mp_reference(struct puffs_mount *pmp)
    551   1.22.2.5     ad {
    552   1.22.2.5     ad 
    553   1.22.2.5     ad 	KASSERT(mutex_owned(&pmp->pmp_lock));
    554   1.22.2.5     ad 	pmp->pmp_refcount++;
    555   1.22.2.5     ad }
    556   1.22.2.5     ad 
    557   1.22.2.5     ad void
    558   1.22.2.5     ad puffs_mp_release(struct puffs_mount *pmp)
    559   1.22.2.5     ad {
    560   1.22.2.5     ad 
    561   1.22.2.5     ad 	KASSERT(mutex_owned(&pmp->pmp_lock));
    562   1.22.2.5     ad 	if (--pmp->pmp_refcount == 0)
    563   1.22.2.5     ad 		cv_broadcast(&pmp->pmp_refcount_cv);
    564   1.22.2.5     ad }
    565  1.22.2.12     ad 
    566  1.22.2.12     ad void
    567  1.22.2.12     ad puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
    568  1.22.2.12     ad 	int flags)
    569  1.22.2.12     ad {
    570  1.22.2.12     ad 
    571  1.22.2.12     ad 	*eobp = size;
    572  1.22.2.12     ad }
    573  1.22.2.12     ad 
    574  1.22.2.12     ad void
    575  1.22.2.12     ad puffs_gop_markupdate(struct vnode *vp, int flags)
    576  1.22.2.12     ad {
    577  1.22.2.12     ad 	int uflags = 0;
    578  1.22.2.12     ad 
    579  1.22.2.12     ad 	if (flags & GOP_UPDATE_ACCESSED)
    580  1.22.2.12     ad 		uflags |= PUFFS_UPDATEATIME;
    581  1.22.2.12     ad 	if (flags & GOP_UPDATE_MODIFIED)
    582  1.22.2.12     ad 		uflags |= PUFFS_UPDATEMTIME;
    583  1.22.2.12     ad 
    584  1.22.2.12     ad 	puffs_updatenode(vp, uflags);
    585  1.22.2.12     ad }
    586