Home | History | Annotate | Line # | Download | only in puffs
puffs_vnops.c revision 1.2
      1 /*	$NetBSD: puffs_vnops.c,v 1.2 2006/10/23 12:21:39 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Google Summer of Code program and the Ulla Tuominen Foundation.
      8  * The Google SoC project was mentored by Bill Studenmund.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. The name of the company nor the name of the author may be used to
     19  *    endorse or promote products derived from this software without specific
     20  *    prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     25  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 __KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.2 2006/10/23 12:21:39 pooka Exp $");
     37 
     38 #include <sys/param.h>
     39 #include <sys/vnode.h>
     40 #include <sys/mount.h>
     41 #include <sys/malloc.h>
     42 #include <sys/namei.h>
     43 
     44 #include <fs/puffs/puffs_msgif.h>
     45 #include <fs/puffs/puffs_sys.h>
     46 
     47 #include <miscfs/genfs/genfs.h>
     48 
     49 int	puffs_lookup(void *);
     50 int	puffs_create(void *);
     51 int	puffs_access(void *);
     52 int	puffs_mknod(void *);
     53 int	puffs_open(void *);
     54 int	puffs_close(void *);
     55 int	puffs_getattr(void *);
     56 int	puffs_setattr(void *);
     57 int	puffs_revoke(void *);
     58 int	puffs_reclaim(void *);
     59 int	puffs_readdir(void *);
     60 int	puffs_poll(void *);
     61 int	puffs_fsync(void *);
     62 int	puffs_seek(void *);
     63 int	puffs_remove(void *);
     64 int	puffs_mkdir(void *);
     65 int	puffs_rmdir(void *);
     66 int	puffs_link(void *);
     67 int	puffs_readlink(void *);
     68 int	puffs_symlink(void *);
     69 int	puffs_rename(void *);
     70 int	puffs_read(void *);
     71 int	puffs_write(void *);
     72 int	puffs_fcntl(void *);
     73 int	puffs_ioctl(void *);
     74 int	puffs_inactive(void *);
     75 int	puffs_print(void *);
     76 int	puffs_pathconf(void *);
     77 int	puffs_advlock(void *);
     78 
     79 
     80 /* Need to support */
     81 #define puffs_putpages	puffs_generic
     82 #define puffs_getpages	puffs_generic
     83 
     84 /* VOP_LEASE() not included */
     85 
     86 int	puffs_generic(void *);
     87 
     88 #if 0
     89 #define puffs_lock genfs_lock
     90 #define puffs_unlock genfs_unlock
     91 #define puffs_islocked genfs_islocked
     92 #else
     93 int puffs_lock(void *);
     94 int puffs_unlock(void *);
     95 int puffs_islocked(void *);
     96 #endif
     97 
     98 int (**puffs_vnodeop_p)(void *);
     99 const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = {
    100 	{ &vop_default_desc, vn_default_error },
    101 	{ &vop_lookup_desc, puffs_lookup },		/* lookup */
    102 	{ &vop_create_desc, puffs_create },		/* create */
    103         { &vop_mknod_desc, puffs_mknod },		/* mknod */
    104         { &vop_open_desc, puffs_open },			/* open */
    105         { &vop_close_desc, puffs_close },		/* close */
    106         { &vop_access_desc, puffs_access },		/* access */
    107         { &vop_getattr_desc, puffs_getattr },		/* getattr */
    108         { &vop_setattr_desc, puffs_setattr },		/* setattr */
    109         { &vop_read_desc, puffs_read },			/* read */
    110         { &vop_write_desc, puffs_write },		/* write */
    111         { &vop_fcntl_desc, puffs_fcntl },		/* fcntl */
    112         { &vop_ioctl_desc, puffs_ioctl },		/* ioctl */
    113         { &vop_revoke_desc, puffs_revoke },		/* revoke */
    114         { &vop_fsync_desc, puffs_fsync },		/* fsync */
    115         { &vop_seek_desc, puffs_seek },			/* seek */
    116         { &vop_remove_desc, puffs_remove },		/* remove */
    117         { &vop_link_desc, puffs_link },			/* link */
    118         { &vop_rename_desc, puffs_rename },		/* rename */
    119         { &vop_mkdir_desc, puffs_mkdir },		/* mkdir */
    120         { &vop_rmdir_desc, puffs_rmdir },		/* rmdir */
    121         { &vop_symlink_desc, puffs_symlink },		/* symlink */
    122         { &vop_readdir_desc, puffs_readdir },		/* readdir */
    123         { &vop_readlink_desc, puffs_readlink },		/* readlink */
    124         { &vop_abortop_desc, genfs_abortop },		/* abortop */
    125         { &vop_inactive_desc, puffs_inactive },		/* inactive */
    126         { &vop_reclaim_desc, puffs_reclaim },		/* reclaim */
    127         { &vop_lock_desc, puffs_lock },			/* lock */
    128         { &vop_unlock_desc, puffs_unlock },		/* unlock */
    129         { &vop_bmap_desc, genfs_eopnotsupp },		/* bmap */
    130         { &vop_strategy_desc, genfs_eopnotsupp },	/* strategy */
    131         { &vop_print_desc, puffs_print },		/* print */
    132         { &vop_islocked_desc, puffs_islocked },		/* islocked */
    133         { &vop_pathconf_desc, puffs_pathconf },		/* pathconf */
    134         { &vop_advlock_desc, puffs_advlock },		/* advlock */
    135         { &vop_bwrite_desc, genfs_nullop },		/* bwrite */
    136 #if 0
    137         { &vop_getpages_desc, puffs_getpages },		/* getpages */
    138 #endif
    139         { &vop_putpages_desc, genfs_null_putpages },	/* putpages */
    140 
    141         { &vop_poll_desc, genfs_eopnotsupp },		/* poll XXX */
    142         { &vop_poll_desc, genfs_eopnotsupp },		/* kqfilter XXX */
    143         { &vop_mmap_desc, genfs_eopnotsupp },		/* mmap XXX */
    144 	{ NULL, NULL }
    145 };
    146 const struct vnodeopv_desc puffs_vnodeop_opv_desc =
    147 	{ &puffs_vnodeop_p, puffs_vnodeop_entries };
    148 
    149 #define LOCKEDVP(a) (VOP_ISLOCKED(a) ? (a) : NULL)
    150 
    151 
    152 int
    153 puffs_lookup(void *v)
    154 {
    155         struct vop_lookup_args /* {
    156                 struct vnode * a_dvp;
    157                 struct vnode ** a_vpp;
    158                 struct componentname * a_cnp;
    159         } */ *ap = v;
    160 	struct puffs_mount *pmp;
    161 	struct componentname *cnp;
    162 	struct vnode *vp, *dvp;
    163 	int wantpunlock, isdot;
    164 	int error;
    165 
    166 	PUFFS_VNREQ(lookup);
    167 
    168 	pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
    169 	cnp = ap->a_cnp;
    170 	dvp = ap->a_dvp;
    171 	*ap->a_vpp = NULL;
    172 
    173 	/* first things first: check access */
    174 	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_lwp);
    175 	if (error)
    176 		return error;
    177 
    178 	wantpunlock = ~cnp->cn_flags & (LOCKPARENT | ISLASTCN);
    179 	isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
    180 
    181 	DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %lx\n",
    182 	    cnp->cn_nameptr, dvp, cnp->cn_nameiop));
    183 
    184 	/*
    185 	 * Do sanity checks we can do without consulting userland.
    186 	 */
    187 
    188 	/*
    189 	 * last component check & ro fs
    190 	 *
    191 	 * hmmm... why doesn't this check for create?
    192 	 */
    193 	if ((cnp->cn_flags & ISLASTCN)
    194 	    && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY)
    195 	    && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
    196 		DPRINTF(("puffs_lookup: write lookup for read-only fs!\n"));
    197 		return EROFS;
    198 	}
    199 
    200 	/*
    201 	 * Check if someone fed it into the cache
    202 	 */
    203 	error = cache_lookup(dvp, ap->a_vpp, cnp);
    204 	if (error >= 0)
    205 		return error;
    206 
    207 	if (isdot) {
    208 		vp = ap->a_dvp;
    209 		vref(vp);
    210 		*ap->a_vpp = vp;
    211 		return 0;
    212 	}
    213 
    214 	puffs_makecn(&lookup_arg.pvnr_cn, cnp);
    215 
    216 	if (cnp->cn_flags & ISDOTDOT)
    217 		VOP_UNLOCK(dvp, 0);
    218 
    219 	error = puffs_vntouser(pmp, PUFFS_VN_LOOKUP,
    220 	    &lookup_arg, sizeof(lookup_arg), VPTOPNC(dvp), LOCKEDVP(dvp), NULL);
    221 	DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
    222 
    223 	/*
    224 	 * In case of error, leave parent locked.  There is no new
    225 	 * vnode to play with, so be happy with the NULL value given
    226 	 * to vpp in the beginning.
    227 	 */
    228 	if (error) {
    229 		if (error == -1) {
    230 			if ((cnp->cn_flags & ISLASTCN)
    231 			    && (cnp->cn_nameiop == CREATE
    232 			      || cnp->cn_nameiop == RENAME)) {
    233 				cnp->cn_flags |= SAVENAME;
    234 				error = EJUSTRETURN;
    235 			} else
    236 				/* userspace is on crack */
    237 				error = ENOENT;
    238 		}
    239 		*ap->a_vpp = NULL;
    240 		if (cnp->cn_flags & ISDOTDOT)
    241 			if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0)
    242 				cnp->cn_flags |= PDIRUNLOCK;
    243 		return error;
    244 	}
    245 
    246 	vp = puffs_pnode2vnode(pmp, lookup_arg.pvnr_newnode);
    247 	if (!vp) {
    248 		error = puffs_getvnode(dvp->v_mount,
    249 		    lookup_arg.pvnr_newnode, &vp);
    250 		if (error) {
    251 			if (cnp->cn_flags & ISDOTDOT)
    252 				if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0)
    253 					cnp->cn_flags |= PDIRUNLOCK;
    254 			return error;
    255 		}
    256 		vp->v_type = lookup_arg.pvnr_vtype;
    257 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    258 	}
    259 
    260 	if (cnp->cn_flags & ISDOTDOT) {
    261 		if (cnp->cn_flags & LOCKPARENT &&
    262 		    cnp->cn_flags & ISLASTCN) {
    263 			if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0) {
    264 				cnp->cn_flags |= PDIRUNLOCK;
    265 			}
    266 		}
    267 	} else  {
    268 		if (wantpunlock) {
    269 			VOP_UNLOCK(dvp, 0);
    270 			/* we don't really need to set this? */
    271 			cnp->cn_flags |= PDIRUNLOCK;
    272 		}
    273 	}
    274 
    275 	if (cnp->cn_flags & MAKEENTRY)
    276 		cache_enter(dvp, vp, cnp);
    277 	*ap->a_vpp = vp;
    278 
    279 	return 0;
    280 }
    281 
    282 int
    283 puffs_create(void *v)
    284 {
    285 	struct vop_create_args /* {
    286 		const struct vnodeop_desc *a_desc;
    287 		struct vnode *a_dvp;
    288 		struct vnode **a_vpp;
    289 		struct componentname *a_cnp;
    290 		struct vattr *a_vap;
    291 	} */ *ap = v;
    292 	int error;
    293 
    294 	PUFFS_VNREQ(create);
    295 
    296 	puffs_makecn(&create_arg.pvnr_cn, ap->a_cnp);
    297 	create_arg.pvnr_va = *ap->a_vap;
    298 
    299 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_CREATE,
    300 	    &create_arg, sizeof(create_arg), VPTOPNC(ap->a_dvp),
    301 	    ap->a_dvp, NULL);
    302 	if (error)
    303 		return error;
    304 
    305 	return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
    306 	    create_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type);
    307 }
    308 
    309 int
    310 puffs_mknod(void *v)
    311 {
    312 	struct vop_mknod_args /* {
    313 		const struct vnodeop_desc *a_desc;
    314 		struct vnode *a_dvp;
    315 		struct vnode **a_vpp;
    316 		struct componentname *a_cnp;
    317 		struct vattr *a_vap;
    318 	} */ *ap = v;
    319 	int error;
    320 
    321 	PUFFS_VNREQ(mknod);
    322 
    323 	puffs_makecn(&mknod_arg.pvnr_cn, ap->a_cnp);
    324 	mknod_arg.pvnr_va = *ap->a_vap;
    325 
    326 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_MKNOD,
    327 	    &mknod_arg, sizeof(mknod_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
    328 	if (error)
    329 		return error;
    330 
    331 	return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
    332 	    mknod_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type);
    333 }
    334 
    335 int
    336 puffs_open(void *v)
    337 {
    338 	struct vop_open_args /* {
    339 		const struct vnodeop_desc *a_desc;
    340 		struct vnode *a_vp;
    341 		int a_mode;
    342 		kauth_cred_t a_cred;
    343 		struct lwp *a_l;
    344 	} */ *ap = v;
    345 
    346 	PUFFS_VNREQ(open);
    347 
    348 	open_arg.pvnr_mode = ap->a_mode;
    349 	puffs_credcvt(&open_arg.pvnr_cred, ap->a_cred);
    350 	open_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    351 
    352 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_OPEN,
    353 	    &open_arg, sizeof(open_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
    354 }
    355 
    356 int
    357 puffs_close(void *v)
    358 {
    359 	struct vop_close_args /* {
    360 		const struct vnodeop_desc *a_desc;
    361 		struct vnode *a_vp;
    362 		int a_fflag;
    363 		kauth_cred_t a_cred;
    364 		struct lwp *a_l;
    365 	} */ *ap = v;
    366 
    367 	PUFFS_VNREQ(close);
    368 
    369 	close_arg.pvnr_fflag = ap->a_fflag;
    370 	puffs_credcvt(&close_arg.pvnr_cred, ap->a_cred);
    371 	close_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    372 
    373 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_CLOSE,
    374 	    &close_arg, sizeof(close_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
    375 }
    376 
    377 int
    378 puffs_access(void *v)
    379 {
    380 	struct vop_access_args /* {
    381 		const struct vnodeop_desc *a_desc;
    382 		struct vnode *a_vp;
    383 		int a_mode;
    384 		kauth_cred_t a_cred;
    385 		struct lwp *a_l;
    386 	} */ *ap = v;
    387 	int error;
    388 
    389 	PUFFS_VNREQ(access);
    390 
    391 	access_arg.pvnr_mode = ap->a_mode;
    392 	access_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    393 	puffs_credcvt(&access_arg.pvnr_cred, ap->a_cred);
    394 
    395 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ACCESS,
    396 	    &access_arg, sizeof(access_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
    397 	if (error)
    398 		return error;
    399 
    400 	/*
    401 	 * XXXtothepeople: no execute permissions yet.  Otherwise
    402 	 * all hell will break loose if we try to execute a file
    403 	 * without VOP_GETPAGES support.  It is forthcoming, just
    404 	 * not there yet ...
    405 	 */
    406 	if (ap->a_mode == VEXEC && ap->a_vp->v_type != VDIR)
    407 		return EACCES;
    408 
    409 	return 0;
    410 }
    411 
    412 int
    413 puffs_getattr(void *v)
    414 {
    415 	struct vop_getattr_args /* {
    416 		const struct vnodeop_desc *a_desc;
    417 		struct vnode *a_vp;
    418 		struct vattr *a_vap;
    419 		kauth_cred_t a_cred;
    420 		struct lwp *a_l;
    421 	} */ *ap = v;
    422 	int error;
    423 
    424 	PUFFS_VNREQ(getattr);
    425 
    426 	vattr_null(&getattr_arg.pvnr_va);
    427 	puffs_credcvt(&getattr_arg.pvnr_cred, ap->a_cred);
    428 	getattr_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    429 
    430 	/*
    431 	 * XXX + XX (dos equis): this can't go through the unlock/lock
    432 	 * cycle, since it can be called from uvn_attach(), which fiddles
    433 	 * around with VXLOCK and therefore breaks vn_lock().  Proper
    434 	 * fix pending.
    435 	 */
    436 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_GETATTR,
    437 	    &getattr_arg, sizeof(getattr_arg), VPTOPNC(ap->a_vp),
    438 	    NULL /* XXXseeabove: should be LOCKEDVP(ap->a_vp) */, NULL);
    439 	if (error)
    440 		return error;
    441 
    442 	(void)memcpy(ap->a_vap, &getattr_arg.pvnr_va, sizeof(struct vattr));
    443 
    444 	/*
    445 	 * XXXtothepeople: adjust the return value so that we don't
    446 	 * advertise execute bits.  Otherwise all hell will break
    447 	 * loose if we try to execute a file without VOP_GETPAGES
    448 	 * support.  It is forthcoming, just not there yet ...
    449 	 */
    450 	if (ap->a_vp->v_type != VDIR)
    451 		ap->a_vap->va_mode &= ~0111;
    452 
    453 	return 0;
    454 }
    455 
    456 int
    457 puffs_setattr(void *v)
    458 {
    459 	struct vop_getattr_args /* {
    460 		const struct vnodeop_desc *a_desc;
    461 		struct vnode *a_vp;
    462 		struct vattr *a_vap;
    463 		kauth_cred_t a_cred;
    464 		struct lwp *a_l;
    465 	} */ *ap = v;
    466 
    467 	PUFFS_VNREQ(setattr);
    468 
    469 	(void)memcpy(&setattr_arg.pvnr_va, ap->a_vap, sizeof(struct vattr));
    470 	puffs_credcvt(&setattr_arg.pvnr_cred, ap->a_cred);
    471 	setattr_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    472 
    473 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SETATTR,
    474 	    &setattr_arg, sizeof(setattr_arg), VPTOPNC(ap->a_vp),
    475 	    ap->a_vp, NULL);
    476 }
    477 
    478 int
    479 puffs_revoke(void *v)
    480 {
    481 	struct vop_revoke_args /* {
    482 		const struct vnodeop_desc *a_desc;
    483 		struct vnode *a_vp;
    484 		int a_flags;
    485 	} */ *ap = v;
    486 	PUFFS_VNREQ(revoke);
    487 
    488 	revoke_arg.pvnr_flags = ap->a_flags;
    489 
    490 	/* don't really care if userspace doesn't want to play along */
    491 	puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_REVOKE,
    492 	    &revoke_arg, sizeof(revoke_arg), VPTOPNC(ap->a_vp), NULL, NULL);
    493 
    494 	return genfs_revoke(v);
    495 }
    496 
    497 int
    498 puffs_reclaim(void *v)
    499 {
    500 	struct vop_reclaim_args /* {
    501 		const struct vnodeop_desc *a_desc;
    502 		struct vnode *a_vp;
    503 		struct lwp *a_l;
    504 	} */ *ap = v;
    505 	struct puffs_mount *pmp;
    506 	int error;
    507 
    508 	PUFFS_VNREQ(reclaim);
    509 
    510 	/*
    511 	 * first things first: check if someone is trying to reclaim the
    512 	 * root vnode.  do not allow that to travel to userspace.
    513 	 * Note that we don't need to take the lock similarly to
    514 	 * puffs_root(), since there is only one of us.
    515 	 */
    516 	if (ap->a_vp->v_flag & VROOT) {
    517 		pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
    518 #ifdef DIAGNOSTIC
    519 		simple_lock(&pmp->pmp_lock);
    520 		if (pmp->pmp_root == NULL)
    521 			panic("puffs_reclaim: releasing root vnode (%p) twice",
    522 			    ap->a_vp);
    523 		simple_unlock(&pmp->pmp_lock);
    524 #endif
    525 		pmp->pmp_root = NULL;
    526 		puffs_putvnode(ap->a_vp);
    527 		return 0;
    528 	}
    529 
    530 	reclaim_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    531 
    532 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_RECLAIM,
    533 	    &reclaim_arg, sizeof(reclaim_arg), VPTOPNC(ap->a_vp), NULL, NULL);
    534 #if 0
    535 	/*
    536 	 * XXX: if reclaim fails for any other reason than the userspace
    537 	 * being dead, we should consider unmounting the filesystem, since
    538 	 * we can't trust it to be in a consistent state anymore.  But for
    539 	 * now, just ignore all errors.
    540 	 */
    541 	if (error)
    542 		return error;
    543 #endif
    544 
    545 	puffs_putvnode(ap->a_vp);
    546 
    547 	return 0;
    548 }
    549 
    550 int
    551 puffs_readdir(void *v)
    552 {
    553 	struct vop_readdir_args /* {
    554 		const struct vnodeop_desc *a_desc;
    555 		struct vnode *a_vp;
    556 		struct uio *a_uio;
    557 		kauth_cred_t a_cred;
    558 		int *a_eofflag;
    559 		off_t **a_cookies;
    560 		int *a_ncookies;
    561 	} */ *ap = v;
    562 	struct puffs_vnreq_readdir *readdir_argp;
    563 	size_t argsize;
    564 	struct uio *uio = ap->a_uio;
    565 	size_t howmuch;
    566 	int error;
    567 
    568 	/* worry about these later */
    569 	if (!(ap->a_cookies == NULL && ap->a_ncookies == NULL))
    570 		return EOPNOTSUPP;
    571 
    572 	argsize = sizeof(struct puffs_vnreq_readdir);
    573 	readdir_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK);
    574 
    575 	puffs_credcvt(&readdir_argp->pvnr_cred, ap->a_cred);
    576 	readdir_argp->pvnr_offset = uio->uio_offset;
    577 	readdir_argp->pvnr_resid = uio->uio_resid;
    578 
    579 	error = puffs_vntouser_adjbuf(MPTOPUFFSMP(ap->a_vp->v_mount),
    580 	    PUFFS_VN_READDIR, (void **)&readdir_argp, &argsize,
    581 	    sizeof(struct puffs_vnreq_readdir),
    582 	    VPTOPNC(ap->a_vp), ap->a_vp, NULL);
    583 	if (error)
    584 		goto out;
    585 
    586 	/* userspace is cheating? */
    587 	if (readdir_argp->pvnr_resid > uio->uio_resid) {
    588 		error = EINVAL;
    589 		goto out;
    590 	}
    591 
    592 	/* bouncy-wouncy with the directory data */
    593 	howmuch = uio->uio_resid - readdir_argp->pvnr_resid;
    594 	error = uiomove(readdir_argp->pvnr_dent, howmuch, uio);
    595 	if (error)
    596 		goto out;
    597 	uio->uio_offset = readdir_argp->pvnr_offset;
    598 
    599  out:
    600 	free(readdir_argp, M_PUFFS);
    601 	return error;
    602 }
    603 
    604 int
    605 puffs_poll(void *v)
    606 {
    607 	struct vop_poll_args /* {
    608 		const struct vnodeop_desc *a_desc;
    609 		struct vnode *a_vp;
    610 		int a_events;
    611 		struct lwp *a_l;
    612 	}*/ *ap = v;
    613 
    614 	PUFFS_VNREQ(poll);
    615 
    616 	poll_arg.pvnr_events = ap->a_events;
    617 	poll_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    618 
    619 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_POLL,
    620 	    &poll_arg, sizeof(poll_arg), VPTOPNC(ap->a_vp), NULL, NULL);
    621 }
    622 
    623 int
    624 puffs_fsync(void *v)
    625 {
    626 	struct vop_fsync_args /* {
    627 		const struct vnodeop_desc *a_desc;
    628 		struct vnode *a_vp;
    629 		kauth_cred_t a_cred;
    630 		int a_flags;
    631 		off_t a_offlo;
    632 		off_t a_offhi;
    633 		struct lwp *a_l;
    634 	} */ *ap = v;
    635 
    636 	PUFFS_VNREQ(fsync);
    637 
    638 	puffs_credcvt(&fsync_arg.pvnr_cred, ap->a_cred);
    639 	fsync_arg.pvnr_flags = ap->a_flags;
    640 	fsync_arg.pvnr_offlo = ap->a_offlo;
    641 	fsync_arg.pvnr_offhi = ap->a_offhi;
    642 	fsync_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
    643 
    644 	/*
    645 	 * XXX: see comment at puffs_getattr about locking
    646 	 */
    647 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_FSYNC,
    648 	    &fsync_arg, sizeof(fsync_arg), VPTOPNC(ap->a_vp),
    649 	    NULL /* XXXshouldbe: ap->a_vp */, NULL);
    650 }
    651 
    652 int
    653 puffs_seek(void *v)
    654 {
    655 	struct vop_seek_args /* {
    656 		const struct vnodeop_desc *a_desc;
    657 		struct vnode *a_vp;
    658 		off_t a_oldoff;
    659 		off_t a_newoff;
    660 		kauth_cred_t a_cred;
    661 	} */ *ap = v;
    662 
    663 	PUFFS_VNREQ(seek);
    664 
    665 	seek_arg.pvnr_oldoff = ap->a_oldoff;
    666 	seek_arg.pvnr_newoff = ap->a_newoff;
    667 	puffs_credcvt(&seek_arg.pvnr_cred, ap->a_cred);
    668 
    669 	/*
    670 	 * XXX: seems like seek is called with an unlocked vp, but
    671 	 * it can't hurt to play safe
    672 	 */
    673 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SEEK,
    674 	    &seek_arg, sizeof(seek_arg), VPTOPNC(ap->a_vp),
    675 	    LOCKEDVP(ap->a_vp), NULL);
    676 }
    677 
    678 int
    679 puffs_remove(void *v)
    680 {
    681 	struct vop_remove_args /* {
    682 		const struct vnodeop_desc *a_desc;
    683 		struct vnode *a_dvp;
    684 		struct vnode *a_vp;
    685 		struct componentname *a_cnp;
    686 	} */ *ap = v;
    687 	int error;
    688 
    689 	PUFFS_VNREQ(remove);
    690 
    691 	remove_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
    692 	puffs_makecn(&remove_arg.pvnr_cn, ap->a_cnp);
    693 
    694 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_REMOVE,
    695 	    &remove_arg, sizeof(remove_arg), VPTOPNC(ap->a_dvp),
    696 	    ap->a_dvp, ap->a_vp);
    697 
    698 	vput(ap->a_vp);
    699 	vput(ap->a_dvp);
    700 
    701 	return error;
    702 }
    703 
    704 int
    705 puffs_mkdir(void *v)
    706 {
    707 	struct vop_mkdir_args /* {
    708 		const struct vnodeop_desc *a_desc;
    709 		struct vnode *a_dvp;
    710 		struct vnode **a_vpp;
    711 		struct componentname *a_cnp;
    712 		struct vattr *a_vap;
    713 	} */ *ap = v;
    714 	int error;
    715 
    716 	PUFFS_VNREQ(mkdir);
    717 
    718 	puffs_makecn(&mkdir_arg.pvnr_cn, ap->a_cnp);
    719 	mkdir_arg.pvnr_va = *ap->a_vap;
    720 
    721 	/* XXX: wouldn't need to relock dvp, but that's life */
    722 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_MKDIR,
    723 	    &mkdir_arg, sizeof(mkdir_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
    724 	if (error)
    725 		return error;
    726 
    727 	return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
    728 	    mkdir_arg.pvnr_newnode, ap->a_cnp, VDIR);
    729 }
    730 
    731 int
    732 puffs_rmdir(void *v)
    733 {
    734 	struct vop_rmdir_args /* {
    735 		const struct vnodeop_desc *a_desc;
    736 		struct vnode *a_dvp;
    737 		struct vnode *a_vp;
    738 		struct componentname *a_cnp;
    739 	} */ *ap = v;
    740 	int error;
    741 
    742 	PUFFS_VNREQ(rmdir);
    743 
    744 	rmdir_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
    745 	puffs_makecn(&rmdir_arg.pvnr_cn, ap->a_cnp);
    746 
    747 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_RMDIR,
    748 	    &rmdir_arg, sizeof(rmdir_arg), VPTOPNC(ap->a_dvp),
    749 	    ap->a_dvp, ap->a_vp);
    750 
    751 	vput(ap->a_dvp);
    752 	vput(ap->a_vp);
    753 
    754 	return error;
    755 }
    756 
    757 int
    758 puffs_link(void *v)
    759 {
    760 	struct vop_link_args /* {
    761 		const struct vnodeop_desc *a_desc;
    762 		struct vnode *a_dvp;
    763 		struct vnode *a_vp;
    764 		struct componentname *a_cnp;
    765 	}*/ *ap = v;
    766 	int error;
    767 
    768 	PUFFS_VNREQ(link);
    769 
    770 	link_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
    771 	puffs_makecn(&link_arg.pvnr_cn, ap->a_cnp);
    772 
    773 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_LINK,
    774 	    &link_arg, sizeof(link_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
    775 
    776 	vput(ap->a_dvp);
    777 
    778 	return error;
    779 }
    780 
    781 int
    782 puffs_symlink(void *v)
    783 {
    784 	struct vop_symlink_args /* {
    785 		const struct vnodeop_desc *a_desc;
    786 		struct vnode *a_dvp;
    787 		struct vnode **a_vpp;
    788 		struct componentname *a_cnp;
    789 		struct vattr *a_vap;
    790 		char *a_target;
    791 	}*/ *ap = v;
    792 	int error;
    793 
    794 	PUFFS_VNREQ(symlink); /* XXX: large structure */
    795 
    796 	*ap->a_vpp = NULL;
    797 
    798 	puffs_makecn(&symlink_arg.pvnr_cn, ap->a_cnp);
    799 	symlink_arg.pvnr_va = *ap->a_vap;
    800 	(void)strlcpy(symlink_arg.pvnr_link, ap->a_target,
    801 	    sizeof(symlink_arg.pvnr_link));
    802 
    803 	/* XXX: don't need to relock parent */
    804 	error =  puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount),
    805 	    PUFFS_VN_SYMLINK, &symlink_arg, sizeof(symlink_arg),
    806 	    VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
    807 	if (error)
    808 		return error;
    809 
    810 	return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
    811 	    symlink_arg.pvnr_newnode, ap->a_cnp, VLNK);
    812 }
    813 
    814 int
    815 puffs_readlink(void *v)
    816 {
    817 	struct vop_readlink_args /* {
    818 		const struct vnodeop_desc *a_desc;
    819 		struct vnode *a_vp;
    820 		struct uio *a_uio;
    821 		kauth_cred_t a_cred;
    822 	} */ *ap = v;
    823 	int error;
    824 
    825 	PUFFS_VNREQ(readlink);
    826 
    827 	puffs_credcvt(&readlink_arg.pvnr_cred, ap->a_cred);
    828 	readlink_arg.pvnr_linklen = sizeof(readlink_arg.pvnr_link);
    829 
    830 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
    831 	    PUFFS_VN_READLINK, &readlink_arg, sizeof(readlink_arg),
    832 	    VPTOPNC(ap->a_vp), ap->a_vp, NULL);
    833 	if (error)
    834 		return error;
    835 
    836 	readlink_arg.pvnr_link[readlink_arg.pvnr_linklen] = '\0';
    837 	return uiomove(&readlink_arg.pvnr_link, readlink_arg.pvnr_linklen,
    838 	    ap->a_uio);
    839 }
    840 
    841 /* XXXXXXX: think about locking & userspace op delocking... */
    842 int
    843 puffs_rename(void *v)
    844 {
    845 	struct vop_rename_args /* {
    846 		const struct vnodeop_desc *a_desc;
    847 		struct vnode *a_fdvp;
    848 		struct vnode *a_fvp;
    849 		struct componentname *a_fcnp;
    850 		struct vnode *a_tdvp;
    851 		struct vnode *a_tvp;
    852 		struct componentname *a_tcnp;
    853 	}*/ *ap = v;
    854 	int error;
    855 
    856 	PUFFS_VNREQ(rename);
    857 
    858 	/*
    859 	 * participate in the duck hunt
    860 	 * (I could do with some canard a la presse, so hopefully
    861 	 *  this is succesful)
    862 	 */
    863 	KASSERT(ap->a_tdvp != ap->a_tvp);
    864 
    865 	if (ap->a_fvp->v_mount != ap->a_tdvp->v_mount) {
    866 		error = EXDEV;
    867 		goto out;
    868 	}
    869 
    870 	rename_arg.pvnr_cookie_src = VPTOPNC(ap->a_fvp);
    871 	rename_arg.pvnr_cookie_targdir = VPTOPNC(ap->a_tdvp);
    872 	if (ap->a_tvp)
    873 		rename_arg.pvnr_cookie_targ = VPTOPNC(ap->a_tvp);
    874 	else
    875 		rename_arg.pvnr_cookie_targ = NULL;
    876 	puffs_makecn(&rename_arg.pvnr_cn_src, ap->a_fcnp);
    877 	puffs_makecn(&rename_arg.pvnr_cn_targ, ap->a_tcnp);
    878 
    879 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_fdvp->v_mount),
    880 	    PUFFS_VN_RENAME, &rename_arg, sizeof(rename_arg),
    881 	    VPTOPNC(ap->a_fdvp), NULL, NULL);
    882 
    883  out:
    884 	vput(ap->a_tdvp);
    885 	if (ap->a_tvp != NULL)
    886 		vput(ap->a_tvp);
    887 
    888 	vrele(ap->a_fdvp);
    889 	vrele(ap->a_fvp);
    890 
    891 	return error;
    892 }
    893 
    894 int
    895 puffs_read(void *v)
    896 {
    897 	struct vop_read_args /* {
    898 		const struct vnodeop_desc *a_desc;
    899 		struct vnode *a_vp;
    900 		struct uio *a_uio;
    901 		int a_ioflag;
    902 		kauth_cred_t a_cred;
    903 	} */ *ap = v;
    904 	struct puffs_vnreq_read *read_argp;
    905 	struct puffs_mount *pmp;
    906 	struct uio *uio;
    907 	size_t tomove, argsize;
    908 	int error;
    909 
    910 	uio = ap->a_uio;
    911 
    912 	pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
    913 	tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
    914 	argsize = sizeof(struct puffs_vnreq_read);
    915 	read_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
    916 
    917 	error = 0;
    918 	while (uio->uio_resid > 0) {
    919 		read_argp->pvnr_ioflag = ap->a_ioflag;
    920 		read_argp->pvnr_resid = tomove;
    921 		read_argp->pvnr_offset = uio->uio_offset;
    922 		puffs_credcvt(&read_argp->pvnr_cred, ap->a_cred);
    923 
    924 		argsize = sizeof(struct puffs_vnreq_read);
    925 		error = puffs_vntouser_adjbuf(pmp, PUFFS_VN_READ,
    926 		    (void **)&read_argp, &argsize,
    927 		    sizeof(struct puffs_vnreq_read), VPTOPNC(ap->a_vp),
    928 		    ap->a_vp, NULL);
    929 		if (error)
    930 			goto out;
    931 
    932 		if (read_argp->pvnr_resid > tomove) {
    933 			error = EINVAL;
    934 			goto out;
    935 		}
    936 
    937 		error = uiomove(read_argp->pvnr_data,
    938 		    tomove - read_argp->pvnr_resid, uio);
    939 
    940 		/*
    941 		 * in case the file is out of juice, resid from userspace
    942 		 * is != 0.  and the error-case is quite obvious
    943 		 */
    944 		if (error || read_argp->pvnr_resid)
    945 			goto out;
    946 
    947 		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
    948 	}
    949 
    950  out:
    951 	free(read_argp, M_PUFFS);
    952 	return error;
    953 }
    954 
    955 int
    956 puffs_write(void *v)
    957 {
    958 	struct vop_write_args /* {
    959 		const struct vnodeop_desc *a_desc;
    960 		struct vnode *a_vp;
    961 		struct uio *a_uio;
    962 		int a_ioflag;
    963 		kauth_cred_t a_cred;
    964 	}*/ *ap = v;
    965 	struct puffs_vnreq_write *write_argp;
    966 	struct puffs_mount *pmp;
    967 	struct uio *uio;
    968 	size_t tomove, argsize;
    969 	int error;
    970 
    971 	uio = ap->a_uio;
    972 
    973 	pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
    974 	tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
    975 	argsize = sizeof(struct puffs_vnreq_write) + tomove;
    976 	write_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
    977 
    978 	error = 0;
    979 	while (uio->uio_resid > 0) {
    980 		write_argp->pvnr_ioflag = ap->a_ioflag;
    981 		write_argp->pvnr_resid = tomove;
    982 		write_argp->pvnr_offset = uio->uio_offset;
    983 		puffs_credcvt(&write_argp->pvnr_cred, ap->a_cred);
    984 		error = uiomove(write_argp->pvnr_data, tomove, ap->a_uio);
    985 		if (error)
    986 			goto out;
    987 
    988 		error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
    989 		    PUFFS_VN_WRITE, write_argp, argsize, VPTOPNC(ap->a_vp),
    990 		    ap->a_vp, NULL);
    991 		if (error) {
    992 			/* restore uiomove */
    993 			uio->uio_resid += tomove;
    994 			uio->uio_offset -= tomove;
    995 			goto out;
    996 		}
    997 		if (write_argp->pvnr_resid > tomove) {
    998 			error = EINVAL;
    999 			goto out;
   1000 		}
   1001 
   1002 		/* didn't move everything?  bad userspace.  bail */
   1003 		if (write_argp->pvnr_resid != 0) {
   1004 			uio->uio_resid += write_argp->pvnr_resid;
   1005 			uio->uio_offset -= write_argp->pvnr_resid;
   1006 			error = EIO;
   1007 			break;
   1008 		}
   1009 
   1010 		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
   1011 	}
   1012 
   1013  out:
   1014 	free(write_argp, M_PUFFS);
   1015 	return error;
   1016 }
   1017 
   1018 static int	puffs_fcnioctl(struct vop_ioctl_args * /*XXX*/, int);
   1019 
   1020 #define FCNIOCTL_ARG_MAX 1<<16
   1021 int
   1022 puffs_fcnioctl(struct vop_ioctl_args *ap, int puffsop)
   1023 {
   1024 	/* struct vop_ioctl_args {
   1025 		const struct vnodeop_desc *a_desc;
   1026 		struct vnode *a_vp;
   1027 		u_long a_command;
   1028 		void *a_data;
   1029 		int a_fflag;
   1030 		kauth_cred_t a_cred;
   1031 		struct lwp *a_l;
   1032 	}*ap = v; */
   1033 	struct puffs_mount *pmp;
   1034 	struct puffs_sizepark pspark;
   1035 	void *kernbuf;
   1036 	size_t copylen;
   1037 	int error;
   1038 
   1039 	PUFFS_VNREQ(fcnioctl);
   1040 
   1041 	/*
   1042 	 * Since this op gives the filesystem (almost) complete control on
   1043 	 * how much it is allowed to copy from the calling process
   1044 	 * address space, do not enable it by default, since it would
   1045 	 * be a whopping security hole.
   1046 	 */
   1047 	pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
   1048 	if ((pmp->pmp_args.pa_flags & PUFFS_FLAG_ALLOWCTL) == 0)
   1049 		return EINVAL; /* only shoe that fits */
   1050 
   1051 	/* fill in sizereq and store it */
   1052 	pspark.pkso_reqid = puffs_getreqid(pmp);
   1053 	pspark.pkso_reqtype = PUFFS_SIZEOPREQ_BUF_IN;
   1054 	pspark.pkso_copybuf = ap->a_data;
   1055 	pspark.pkso_bufsize = FCNIOCTL_ARG_MAX;
   1056 	TAILQ_INSERT_TAIL(&pmp->pmp_req_sizepark, &pspark, pkso_entries);
   1057 
   1058 	/* then fill in actual request and shoot it off */
   1059 	fcnioctl_arg.pvnr_command = ap->a_command;
   1060 	fcnioctl_arg.pvnr_fflag = ap->a_fflag;
   1061 	puffs_credcvt(&fcnioctl_arg.pvnr_cred, ap->a_cred);
   1062 	fcnioctl_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
   1063 
   1064 	error = puffs_vntouser_req(MPTOPUFFSMP(ap->a_vp->v_mount), puffsop,
   1065 	    &fcnioctl_arg, sizeof(fcnioctl_arg), VPTOPNC(ap->a_vp),
   1066 	    pspark.pkso_reqid, NULL, NULL);
   1067 
   1068 	/* if we don't need to copy data, we're done */
   1069 	if (error || !fcnioctl_arg.pvnr_copyback)
   1070 		return error;
   1071 
   1072 	copylen = MIN(FCNIOCTL_ARG_MAX, fcnioctl_arg.pvnr_datalen);
   1073 	kernbuf = malloc(copylen, M_PUFFS, M_WAITOK);
   1074 	error = copyin(fcnioctl_arg.pvnr_data, kernbuf, copylen);
   1075 	if (error)
   1076 		goto out;
   1077 	error = copyout(kernbuf, ap->a_data, copylen);
   1078 
   1079  out:
   1080 	free(kernbuf, M_PUFFS);
   1081 	return error;
   1082 }
   1083 
   1084 int
   1085 puffs_ioctl(void *v)
   1086 {
   1087 
   1088 	return puffs_fcnioctl(v, PUFFS_VN_IOCTL);
   1089 }
   1090 
   1091 int
   1092 puffs_fcntl(void *v)
   1093 {
   1094 
   1095 	return puffs_fcnioctl(v, PUFFS_VN_FCNTL);
   1096 }
   1097 
   1098 int
   1099 puffs_print(void *v)
   1100 {
   1101 	struct vop_print_args /* {
   1102 		struct vnode *a_vp;
   1103 	} */ *ap = v;
   1104 	struct vnode *vp = ap->a_vp;
   1105 	struct puffs_node *pn = vp->v_data;
   1106 
   1107 	PUFFS_VNREQ(print);
   1108 
   1109 	/* kernel portion */
   1110 	printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
   1111 	    "    userspace cookie: %p\n", vp, pn, pn->pn_cookie);
   1112 	lockmgr_printinfo(&vp->v_lock);
   1113 
   1114 	/* userspace portion */
   1115 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_PRINT,
   1116 	    &print_arg, sizeof(print_arg), VPTOPNC(ap->a_vp),
   1117 	    LOCKEDVP(ap->a_vp), NULL);
   1118 }
   1119 
   1120 int
   1121 puffs_pathconf(void *v)
   1122 {
   1123 	struct vop_pathconf_args /* {
   1124 		const struct vnodeop_desc *a_desc;
   1125 		struct vnode *a_vp;
   1126 		int a_name;
   1127 		register_t *a_retval;
   1128 	} */ *ap = v;
   1129 	int error;
   1130 
   1131 	PUFFS_VNREQ(pathconf);
   1132 
   1133 	pathconf_arg.pvnr_name = ap->a_name;
   1134 
   1135 	error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
   1136 	    PUFFS_VN_PATHCONF, &pathconf_arg, sizeof(pathconf_arg),
   1137 	    VPTOPNC(ap->a_vp), ap->a_vp, NULL);
   1138 	if (error)
   1139 		return error;
   1140 
   1141 	*ap->a_retval = pathconf_arg.pvnr_retval;
   1142 
   1143 	return 0;
   1144 }
   1145 
   1146 int
   1147 puffs_advlock(void *v)
   1148 {
   1149 	struct vop_advlock_args /* {
   1150 		const struct vnodeop_desc *a_desc;
   1151 		struct vnode *a_vp;
   1152 		void *a_id;
   1153 		int a_op;
   1154 		struct flock *a_fl;
   1155 		int a_flags;
   1156 	} */ *ap = v;
   1157 	int error;
   1158 
   1159 	PUFFS_VNREQ(advlock);
   1160 
   1161 	error = copyin(ap->a_fl, &advlock_arg.pvnr_fl, sizeof(struct flock));
   1162 	if (error)
   1163 		return error;
   1164 	advlock_arg.pvnr_id = ap->a_id;
   1165 	advlock_arg.pvnr_op = ap->a_op;
   1166 	advlock_arg.pvnr_flags = ap->a_flags;
   1167 
   1168 	return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ADVLOCK,
   1169 	    &advlock_arg, sizeof(advlock_arg), VPTOPNC(ap->a_vp), NULL, NULL);
   1170 }
   1171 
   1172 /*
   1173  * The rest don't get a free trip to userspace and back, they
   1174  * have to stay within the kernel.
   1175  */
   1176 
   1177 /*
   1178  * We don't want to do anything in userspace about this now, we'll
   1179  * simply nuke everything when we reclaim the vnode.
   1180  */
   1181 int
   1182 puffs_inactive(void *v)
   1183 {
   1184 	struct vop_inactive_args /* {
   1185 		const struct vnodeop_desc *a_desc;
   1186 		struct vnode *a_vp;
   1187 		struct lwp *a_l;
   1188 	} */ *ap = v;
   1189 	struct puffs_node *pnode;
   1190 
   1191 	pnode = ap->a_vp->v_data;
   1192 	pnode->pn_stat |= PNODE_INACTIVE;
   1193 	VOP_UNLOCK(ap->a_vp, 0);
   1194 
   1195 	return 0;
   1196 }
   1197 
   1198 /*
   1199  * moreXXX: yes, todo
   1200  */
   1201 int
   1202 puffs_lock(void *v)
   1203 {
   1204 	struct vop_lock_args /* {
   1205 		struct vnode *a_vp;
   1206 		int a_flags;
   1207 	}*/ *ap = v;
   1208 	struct vnode *vp = ap->a_vp;
   1209 
   1210 #if 0
   1211 	DPRINTF(("puffs_lock: lock %p, args 0x%x\n", vp, ap->a_flags));
   1212 #endif
   1213 
   1214 	return lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock);
   1215 }
   1216 
   1217 int
   1218 puffs_unlock(void *v)
   1219 {
   1220 	struct vop_unlock_args /* {
   1221 		struct vnode *a_vp;
   1222 		int a_flags;
   1223 	} */ *ap = v;
   1224 	struct vnode *vp = ap->a_vp;
   1225 
   1226 #if 0
   1227 	DPRINTF(("puffs_unlock: lock %p, args 0x%x\n", vp, ap->a_flags));
   1228 #endif
   1229 
   1230 	return lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock);
   1231 }
   1232 
   1233 int
   1234 puffs_islocked(void *v)
   1235 {
   1236 	struct vop_islocked_args *ap = v;
   1237 	int rv;
   1238 
   1239 	rv = lockstatus(&ap->a_vp->v_lock);
   1240 	return rv;
   1241 }
   1242 
   1243 #if 0
   1244 int
   1245 puffs_getpages(void *v)
   1246 {
   1247 	struct vop_getpages_args /* {
   1248 		const struct vnodeop_desc *a_desc;
   1249 		struct vnode *a_vp;
   1250 		voff_t a_offset;
   1251 		struct vm_page **a_m;
   1252 		int *a_count;
   1253 		int a_centeridx;
   1254 		vm_prot_t a_access_type;
   1255 		int a_advice;
   1256 		int a_flags;
   1257 	} */ *ap = v;
   1258 
   1259 
   1260 }
   1261 #endif
   1262 
   1263 int
   1264 puffs_generic(void *v)
   1265 {
   1266 	struct vop_generic_args *ap = v;
   1267 
   1268 	(void)ap;
   1269 	DPRINTF(("puffs_generic: ap->a_desc = %s\n", ap->a_desc->vdesc_name));
   1270 
   1271 	return EOPNOTSUPP;
   1272 }
   1273