Home | History | Annotate | Line # | Download | only in puffs
puffs_msgif.c revision 1.6
      1 /*	$NetBSD: puffs_msgif.c,v 1.6 2006/11/14 19:36:50 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_msgif.c,v 1.6 2006/11/14 19:36:50 pooka Exp $");
     37 
     38 #include <sys/param.h>
     39 #include <sys/conf.h>
     40 #include <sys/malloc.h>
     41 #include <sys/mount.h>
     42 #include <sys/socketvar.h>
     43 #include <sys/vnode.h>
     44 #include <sys/file.h>
     45 #include <sys/filedesc.h>
     46 #include <sys/lock.h>
     47 #include <sys/poll.h>
     48 
     49 #include <fs/puffs/puffs_msgif.h>
     50 #include <fs/puffs/puffs_sys.h>
     51 
     52 #include <miscfs/syncfs/syncfs.h> /* XXX: for syncer_lock reference */
     53 
     54 
     55 /*
     56  * kernel-user-kernel waitqueues
     57  */
     58 
     59 static int touser(struct puffs_mount *, struct puffs_park *, uint64_t,
     60 		  struct vnode *, struct vnode *);
     61 
     62 uint64_t
     63 puffs_getreqid(struct puffs_mount *pmp)
     64 {
     65 	unsigned int rv;
     66 
     67 	simple_lock(&pmp->pmp_lock);
     68 	rv = pmp->pmp_nextreq++;
     69 	simple_unlock(&pmp->pmp_lock);
     70 
     71 	return rv;
     72 }
     73 
     74 /* vfs request */
     75 int
     76 puffs_vfstouser(struct puffs_mount *pmp, int optype, void *kbuf, size_t buflen)
     77 {
     78 	struct puffs_park park;
     79 
     80 	memset(&park.park_preq, 0, sizeof(struct puffs_req));
     81 
     82 	park.park_opclass = PUFFSOP_VFS;
     83 	park.park_optype = optype;
     84 
     85 	park.park_kernbuf = kbuf;
     86 	park.park_buflen = buflen;
     87 	park.park_copylen = buflen;
     88 	park.park_flags = 0;
     89 
     90 	return touser(pmp, &park, puffs_getreqid(pmp), NULL, NULL);
     91 }
     92 
     93 /*
     94  * vnode level request
     95  */
     96 int
     97 puffs_vntouser(struct puffs_mount *pmp, int optype,
     98 	void *kbuf, size_t buflen, void *cookie,
     99 	struct vnode *vp1, struct vnode *vp2)
    100 {
    101 	struct puffs_park park;
    102 
    103 	memset(&park.park_preq, 0, sizeof(struct puffs_req));
    104 
    105 	park.park_opclass = PUFFSOP_VN;
    106 	park.park_optype = optype;
    107 	park.park_cookie = cookie;
    108 
    109 	park.park_kernbuf = kbuf;
    110 	park.park_buflen = buflen;
    111 	park.park_copylen = buflen;
    112 	park.park_flags = 0;
    113 
    114 	return touser(pmp, &park, puffs_getreqid(pmp), vp1, vp2);
    115 }
    116 
    117 /*
    118  * vnode level request, caller-controller req id
    119  */
    120 int
    121 puffs_vntouser_req(struct puffs_mount *pmp, int optype,
    122 	void *kbuf, size_t buflen, void *cookie, uint64_t reqid,
    123 	struct vnode *vp1, struct vnode *vp2)
    124 {
    125 	struct puffs_park park;
    126 
    127 	memset(&park.park_preq, 0, sizeof(struct puffs_req));
    128 
    129 	park.park_opclass = PUFFSOP_VN;
    130 	park.park_optype = optype;
    131 	park.park_cookie = cookie;
    132 
    133 	park.park_kernbuf = kbuf;
    134 	park.park_buflen = buflen;
    135 	park.park_copylen = buflen;
    136 	park.park_flags = 0;
    137 
    138 	return touser(pmp, &park, reqid, vp1, vp2);
    139 }
    140 
    141 /*
    142  * vnode level request, copy routines can adjust "kernbuf"
    143  */
    144 int
    145 puffs_vntouser_adjbuf(struct puffs_mount *pmp, int optype,
    146 	void **kbuf, size_t *buflen, size_t copylen, void *cookie,
    147 	struct vnode *vp1, struct vnode *vp2)
    148 {
    149 	struct puffs_park park;
    150 	int error;
    151 
    152 	memset(&park.park_preq, 0, sizeof(struct puffs_req));
    153 
    154 	park.park_opclass = PUFFSOP_VN;
    155 	park.park_optype = optype;
    156 	park.park_cookie = cookie;
    157 
    158 	park.park_kernbuf = *kbuf;
    159 	park.park_buflen = *buflen;
    160 	park.park_copylen = copylen;
    161 	park.park_flags = PUFFS_REQFLAG_ADJBUF;
    162 
    163 	error = touser(pmp, &park, puffs_getreqid(pmp), vp1, vp2);
    164 	*kbuf = park.park_kernbuf;
    165 	*buflen = park.park_buflen;
    166 
    167 	return error;
    168 }
    169 
    170 /*
    171  * Notice: kbuf will be free'd later.  I must be allocated from the
    172  * kernel heap and it's ownership is shifted to this function from
    173  * now on, i.e. the caller is not allowed to use it anymore!
    174  */
    175 void
    176 puffs_vntouser_faf(struct puffs_mount *pmp, int optype,
    177 	void *kbuf, size_t buflen, void *cookie)
    178 {
    179 	struct puffs_park *ppark;
    180 
    181 	/* XXX: is it allowable to sleep here? */
    182 	ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_NOWAIT | M_ZERO);
    183 	if (ppark == NULL)
    184 		return; /* 2bad */
    185 
    186 	ppark->park_opclass = PUFFSOP_VN | PUFFSOPFLAG_FAF;
    187 	ppark->park_optype = optype;
    188 	ppark->park_cookie = cookie;
    189 
    190 	ppark->park_kernbuf = kbuf;
    191 	ppark->park_buflen = buflen;
    192 	ppark->park_copylen = buflen;
    193 
    194 	(void)touser(pmp, ppark, 0, NULL, NULL);
    195 }
    196 
    197 /*
    198  * Wait for the userspace ping-pong game in calling process context.
    199  *
    200  * This unlocks vnodes if they are supplied.  vp1 is the vnode
    201  * before in the locking order, i.e. the one which must be locked
    202  * before accessing vp2.  This is done here so that operations are
    203  * already ordered in the queue when vnodes are unlocked (I'm not
    204  * sure if that's really necessary, but it can't hurt).  Okok, maybe
    205  * there's a slight ugly-factor also, but let's not worry about that.
    206  */
    207 static int
    208 touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid,
    209 	struct vnode *vp1, struct vnode *vp2)
    210 {
    211 
    212 	simple_lock(&pmp->pmp_lock);
    213 	if (pmp->pmp_status != PUFFSTAT_RUNNING
    214 	    && pmp->pmp_status != PUFFSTAT_MOUNTING) {
    215 		simple_unlock(&pmp->pmp_lock);
    216 		return ENXIO;
    217 	}
    218 
    219 	ppark->park_id = reqid;
    220 
    221 	TAILQ_INSERT_TAIL(&pmp->pmp_req_touser, ppark, park_entries);
    222 	pmp->pmp_req_touser_waiters++;
    223 
    224 	/*
    225 	 * Don't do unlock-relock dance yet.  There are a couple of
    226 	 * unsolved issues with it.  If we don't unlock, we can have
    227 	 * processes wanting vn_lock in case userspace hangs.  But
    228 	 * that can be "solved" by killing the userspace process.  It
    229 	 * would of course be nicer to have antilocking in the userspace
    230 	 * interface protocol itself.. your patience will be rewarded.
    231 	 */
    232 #if 0
    233 	/* unlock */
    234 	if (vp2)
    235 		VOP_UNLOCK(vp2, 0);
    236 	if (vp1)
    237 		VOP_UNLOCK(vp1, 0);
    238 #endif
    239 
    240 	/*
    241 	 * XXX: does releasing the lock here cause trouble?  Can't hold
    242 	 * it, because otherwise the below would cause locking against
    243 	 * oneself-problems in the kqueue stuff.  yes, it is a
    244 	 * theoretical race, so it must be solved
    245 	 */
    246 	simple_unlock(&pmp->pmp_lock);
    247 
    248 	wakeup(&pmp->pmp_req_touser);
    249 	selnotify(pmp->pmp_sel, 0);
    250 
    251 	if (PUFFSOP_WANTREPLY(ppark->park_opclass))
    252 		ltsleep(ppark, PUSER, "puffs1", 0, NULL);
    253 
    254 #if 0
    255 	/* relock */
    256 	if (vp1)
    257 		KASSERT(vn_lock(vp1, LK_EXCLUSIVE | LK_RETRY) == 0);
    258 	if (vp2)
    259 		KASSERT(vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY) == 0);
    260 #endif
    261 
    262 	return ppark->park_rv;
    263 }
    264 
    265 /*
    266  * We're dead, kaput, RIP, slightly more than merely pining for the
    267  * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
    268  * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!
    269  */
    270 void
    271 puffs_userdead(struct puffs_mount *pmp)
    272 {
    273 	struct puffs_park *park;
    274 
    275 	simple_lock(&pmp->pmp_lock);
    276 
    277 	/*
    278 	 * Mark filesystem status as dying so that operations don't
    279 	 * attempt to march to userspace any longer.
    280 	 */
    281 	pmp->pmp_status = PUFFSTAT_DYING;
    282 
    283 	/* and wakeup processes waiting for a reply from userspace */
    284 	TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) {
    285 		park->park_rv = ENXIO;
    286 		TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries);
    287 		wakeup(park);
    288 	}
    289 
    290 	/* wakeup waiters for completion of vfs/vnode requests */
    291 	TAILQ_FOREACH(park, &pmp->pmp_req_touser, park_entries) {
    292 		park->park_rv = ENXIO;
    293 		TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries);
    294 		wakeup(park);
    295 	}
    296 
    297 	simple_unlock(&pmp->pmp_lock);
    298 }
    299 
    300 
    301 /*
    302  * Device routines
    303  */
    304 
    305 dev_type_open(puffscdopen);
    306 dev_type_close(puffscdclose);
    307 dev_type_ioctl(puffscdioctl);
    308 
    309 /* dev */
    310 const struct cdevsw puffs_cdevsw = {
    311 	puffscdopen,	puffscdclose,	noread,		nowrite,
    312 	noioctl,	nostop,		notty,		nopoll,
    313 	nommap,		nokqfilter,	D_OTHER
    314 };
    315 
    316 static int puffs_fop_read(struct file *, off_t *, struct uio *,
    317 			  kauth_cred_t, int);
    318 static int puffs_fop_write(struct file *, off_t *, struct uio *,
    319 			   kauth_cred_t, int);
    320 static int puffs_fop_ioctl(struct file*, u_long, void *, struct lwp *);
    321 static int puffs_fop_poll(struct file *, int, struct lwp *);
    322 static int puffs_fop_close(struct file *, struct lwp *);
    323 static int puffs_fop_kqfilter(struct file *, struct knote *);
    324 
    325 
    326 /* fd routines, for cloner */
    327 static const struct fileops puffs_fileops = {
    328 	puffs_fop_read,
    329 	puffs_fop_write,
    330 	puffs_fop_ioctl,
    331 	fnullop_fcntl,
    332 	puffs_fop_poll,
    333 	fbadop_stat,
    334 	puffs_fop_close,
    335 	puffs_fop_kqfilter
    336 };
    337 
    338 /*
    339  * puffs instance structures.  these are always allocated and freed
    340  * from the context of the device node / fileop code.
    341  */
    342 struct puffs_instance {
    343 	pid_t pi_pid;
    344 	int pi_idx;
    345 	int pi_fd;
    346 	struct puffs_mount *pi_pmp;
    347 	struct selinfo pi_sel;
    348 
    349 	TAILQ_ENTRY(puffs_instance) pi_entries;
    350 };
    351 #define PMP_EMBRYO ((struct puffs_mount *)-1)	/* before mount	*/
    352 #define PMP_DEAD ((struct puffs_mount *)-2)	/* goner	*/
    353 
    354 static TAILQ_HEAD(, puffs_instance) puffs_ilist
    355     = TAILQ_HEAD_INITIALIZER(puffs_ilist);
    356 
    357 /* protects both the list and the contents of the list elements */
    358 static struct simplelock pi_lock = SIMPLELOCK_INITIALIZER;
    359 
    360 static int get_pi_idx(struct puffs_instance *);
    361 
    362 /* search sorted list of instances for free minor, sorted insert arg */
    363 static int
    364 get_pi_idx(struct puffs_instance *pi_i)
    365 {
    366 	struct puffs_instance *pi;
    367 	int i;
    368 
    369 	i = 0;
    370 	TAILQ_FOREACH(pi, &puffs_ilist, pi_entries) {
    371 		if (i == PUFFS_CLONER)
    372 			return PUFFS_CLONER;
    373 		if (i != pi->pi_idx)
    374 			break;
    375 		i++;
    376 	}
    377 
    378 	pi_i->pi_pmp = PMP_EMBRYO;
    379 
    380 	if (pi == NULL)
    381 		TAILQ_INSERT_TAIL(&puffs_ilist, pi_i, pi_entries);
    382 	else
    383 		TAILQ_INSERT_BEFORE(pi, pi_i, pi_entries);
    384 
    385 	return i;
    386 }
    387 
    388 int
    389 puffscdopen(dev_t dev, int flags, int fmt, struct lwp *l)
    390 {
    391 	struct puffs_instance *pi;
    392 	struct file *fp;
    393 	int error, fd, idx;
    394 
    395 	/*
    396 	 * XXX: decide on some security model and check permissions
    397 	 */
    398 
    399 	if (minor(dev) != PUFFS_CLONER)
    400 		return ENXIO;
    401 
    402 	if ((error = falloc(l, &fp, &fd)) != 0)
    403 		return error;
    404 
    405 	MALLOC(pi, struct puffs_instance *, sizeof(struct puffs_instance),
    406 	    M_PUFFS, M_WAITOK | M_ZERO);
    407 
    408 	simple_lock(&pi_lock);
    409 	idx = get_pi_idx(pi);
    410 	if (idx == PUFFS_CLONER) {
    411 		simple_unlock(&pi_lock);
    412 		FREE(pi, M_PUFFS);
    413 		FILE_UNUSE(fp, l);
    414 		ffree(fp);
    415 		return EBUSY;
    416 	}
    417 
    418 	pi->pi_pid = l->l_proc->p_pid;
    419 	pi->pi_idx = idx;
    420 	simple_unlock(&pi_lock);
    421 
    422 	DPRINTF(("puffscdopen: registered embryonic pmp for pid: %d\n",
    423 	    pi->pi_pid));
    424 
    425 	return fdclone(l, fp, fd, FREAD|FWRITE, &puffs_fileops, pi);
    426 }
    427 
    428 int
    429 puffscdclose(dev_t dev, int flags, int fmt, struct lwp *l)
    430 {
    431 
    432 	panic("puffscdclose\n");
    433 
    434 	return 0;
    435 }
    436 
    437 /*
    438  * Set puffs_mount -pointer.  Called from puffs_mount(), which is the
    439  * earliest place that knows about this.
    440  *
    441  * We only want to make sure that the caller had the right to open the
    442  * device, we don't so much care about which context it gets in case
    443  * the same process opened multiple (since they are equal at this point).
    444  */
    445 int
    446 puffs_setpmp(pid_t pid, int fd, struct puffs_mount *pmp)
    447 {
    448 	struct puffs_instance *pi;
    449 	int rv = 1;
    450 
    451 	simple_lock(&pi_lock);
    452 	TAILQ_FOREACH(pi, &puffs_ilist, pi_entries) {
    453 		if (pi->pi_pid == pid && pi->pi_pmp == PMP_EMBRYO) {
    454 			pi->pi_pmp = pmp;
    455 			pi->pi_fd = fd;
    456 			pmp->pmp_sel = &pi->pi_sel;
    457 			rv = 0;
    458 			break;
    459 		    }
    460 	}
    461 	simple_unlock(&pi_lock);
    462 
    463 	return rv;
    464 }
    465 
    466 /*
    467  * Remove mount point from list of instances.  Called from unmount.
    468  */
    469 void
    470 puffs_nukebypmp(struct puffs_mount *pmp)
    471 {
    472 	struct puffs_instance *pi;
    473 
    474 	simple_lock(&pi_lock);
    475 	TAILQ_FOREACH(pi, &puffs_ilist, pi_entries) {
    476 		if (pi->pi_pmp == pmp) {
    477 			TAILQ_REMOVE(&puffs_ilist, pi, pi_entries);
    478 			break;
    479 		}
    480 	}
    481 	if (pi)
    482 		pi->pi_pmp = PMP_DEAD;
    483 
    484 #ifdef DIAGNOSTIC
    485 	else
    486 		panic("puffs_nukebypmp: invalid puffs_mount\n");
    487 #endif /* DIAGNOSTIC */
    488 
    489 	simple_unlock(&pi_lock);
    490 
    491 	DPRINTF(("puffs_nukebypmp: nuked %p\n", pi));
    492 }
    493 
    494 
    495 static int
    496 puffs_fop_read(struct file *fp, off_t *off, struct uio *uio,
    497 	kauth_cred_t cred, int flags)
    498 {
    499 
    500 	printf("READ\n");
    501 	return ENODEV;
    502 }
    503 
    504 static int
    505 puffs_fop_write(struct file *fp, off_t *off, struct uio *uio,
    506 	kauth_cred_t cred, int flags)
    507 {
    508 
    509 	printf("WRITE\n");
    510 	return ENODEV;
    511 }
    512 
    513 /*
    514  * Poll query interface.  The question is only if an event
    515  * can be read from us (and by read I mean ioctl... ugh).
    516  */
    517 #define PUFFPOLL_EVSET (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)
    518 static int
    519 puffs_fop_poll(struct file *fp, int events, struct lwp *l)
    520 {
    521 	struct puffs_mount *pmp = FPTOPMP(fp);
    522 	int revents;
    523 
    524 	if (pmp == PMP_EMBRYO || pmp == PMP_DEAD) {
    525 		printf("puffs_fop_ioctl: puffs %p, not mounted\n", pmp);
    526 		return ENOENT;
    527 	}
    528 
    529 	revents = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
    530 	if ((events & PUFFPOLL_EVSET) == 0)
    531 		return revents;
    532 
    533 	/* check queue */
    534 	simple_lock(&pmp->pmp_lock);
    535 	if (!TAILQ_EMPTY(&pmp->pmp_req_touser))
    536 		revents |= PUFFPOLL_EVSET;
    537 	else
    538 		selrecord(l, pmp->pmp_sel);
    539 	simple_unlock(&pmp->pmp_lock);
    540 
    541 	return revents;
    542 }
    543 
    544 /*
    545  * device close = forced unmount.
    546  *
    547  * unmounting is a frightfully complex operation to avoid races
    548  *
    549  * XXX: if userspace is terminated by a signal, this will be
    550  * called only after the signal is delivered (i.e. after someone tries
    551  * to access the file system).  Also, the first one for a delivery
    552  * will get a free bounce-bounce ride before it can be notified
    553  * that the fs is dead.  I'm not terribly concerned about optimizing
    554  * this for speed ...
    555  */
    556 static int
    557 puffs_fop_close(struct file *fp, struct lwp *l)
    558 {
    559 	struct puffs_instance *pi;
    560 	struct puffs_mount *pmp;
    561 	struct mount *mp;
    562 	int gone;
    563 
    564 	DPRINTF(("puffs_fop_close: device closed, force filesystem unmount\n"));
    565 
    566 	simple_lock(&pi_lock);
    567 	pmp = FPTOPMP(fp);
    568 	/*
    569 	 * First check if the fs was never mounted.  In that case
    570 	 * remove the instance from the list.  If mount is attempted later,
    571 	 * it will simply fail.
    572 	 */
    573 	if (pmp == PMP_EMBRYO) {
    574 		pi = FPTOPI(fp);
    575 		TAILQ_REMOVE(&puffs_ilist, pi, pi_entries);
    576 		simple_unlock(&pi_lock);
    577 		FREE(pi, M_PUFFS);
    578 		return 0;
    579 	}
    580 
    581 	/*
    582 	 * Next, analyze unmount was called and the instance is dead.
    583 	 * In this case we can just free the structure and go home, it
    584 	 * was removed from the list by puffs_nukebypmp().
    585 	 */
    586 	if (pmp == PMP_DEAD) {
    587 		/* would be nice, but don't have a reference to it ... */
    588 		/* KASSERT(pmp_status == PUFFSTAT_DYING); */
    589 		simple_unlock(&pi_lock);
    590 		pi = FPTOPI(fp);
    591 		FREE(pi, M_PUFFS);
    592 		return 0;
    593 	}
    594 
    595 	/*
    596 	 * So we have a reference.  Proceed to unwrap the file system.
    597 	 */
    598 	mp = PMPTOMP(pmp);
    599 	simple_unlock(&pi_lock);
    600 
    601 	/*
    602 	 * Free the waiting callers before proceeding any further.
    603 	 * The syncer might be jogging around in this file system
    604 	 * currently.  If we allow it to go to the userspace of no
    605 	 * return while trying to get the syncer lock, well ...
    606 	 * synclk: I feel happy, I feel fine.
    607 	 * lockmgr: You're not fooling anyone, you know.
    608 	 */
    609 	puffs_userdead(pmp);
    610 
    611 	/*
    612 	 * Detach from VFS.  First do necessary XXX-dance (from
    613 	 * sys_unmount() & other callers of dounmount()
    614 	 *
    615 	 * XXX Freeze syncer.  Must do this before locking the
    616 	 * mount point.  See dounmount() for details.
    617 	 *
    618 	 * XXX2: take a reference to the mountpoint before starting to
    619 	 * wait for syncer_lock.  Otherwise the mointpoint can be
    620 	 * wiped out while we wait.
    621 	 */
    622 	simple_lock(&mp->mnt_slock);
    623 	mp->mnt_wcnt++;
    624 	simple_unlock(&mp->mnt_slock);
    625 
    626 	lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
    627 
    628 	simple_lock(&mp->mnt_slock);
    629 	mp->mnt_wcnt--;
    630 	if (mp->mnt_wcnt == 0)
    631 		wakeup(&mp->mnt_wcnt);
    632 	gone = mp->mnt_iflag & IMNT_GONE;
    633 	simple_unlock(&mp->mnt_slock);
    634 	if (gone)
    635 		return 0;
    636 
    637 	/*
    638 	 * microscopic race condition here (although not with the current
    639 	 * kernel), but can't really fix it without starting a crusade
    640 	 * against vfs_busy(), so let it be, let it be, let it be
    641 	 */
    642 
    643 	/*
    644 	 * The only way vfs_busy() will fail for us is if the filesystem
    645 	 * is already a goner.
    646 	 * XXX: skating on the thin ice of modern calling conventions ...
    647 	 */
    648 	if (vfs_busy(mp, 0, 0)) {
    649 		lockmgr(&syncer_lock, LK_RELEASE, NULL);
    650 		return 0;
    651 	}
    652 
    653 	/* Once we have the mount point, unmount() can't interfere */
    654 	dounmount(mp, MNT_FORCE, l);
    655 
    656 	return 0;
    657 }
    658 
    659 static int puffsgetop(struct puffs_mount *, struct puffs_req *, int);
    660 static int puffsputop(struct puffs_mount *, struct puffs_req *);
    661 static int puffssizeop(struct puffs_mount *, struct puffs_sizeop *);
    662 
    663 static int
    664 puffs_fop_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l)
    665 {
    666 	struct puffs_mount *pmp = FPTOPMP(fp);
    667 
    668 	if (pmp == PMP_EMBRYO || pmp == PMP_DEAD) {
    669 		printf("puffs_fop_ioctl: puffs %p, not mounted\n", pmp);
    670 		return ENOENT;
    671 	}
    672 
    673 	switch (cmd) {
    674 	case PUFFSGETOP:
    675 		return puffsgetop(pmp, data, fp->f_flag & FNONBLOCK);
    676 		break;
    677 
    678 	case PUFFSPUTOP:
    679 		return puffsputop(pmp, data);
    680 		break;
    681 
    682 	case PUFFSSIZEOP:
    683 		return puffssizeop(pmp, data);
    684 		break;
    685 
    686 	case PUFFSSTARTOP:
    687 		return puffs_start2(pmp, data);
    688 
    689 	/* already done in sys_ioctl() */
    690 	case FIONBIO:
    691 		return 0;
    692 
    693 	default:
    694 		return EINVAL;
    695 
    696 	}
    697 }
    698 
    699 static void
    700 filt_puffsdetach(struct knote *kn)
    701 {
    702 	struct puffs_instance *pi = kn->kn_hook;
    703 
    704 	simple_lock(&pi_lock);
    705 	SLIST_REMOVE(&pi->pi_sel.sel_klist, kn, knote, kn_selnext);
    706 	simple_unlock(&pi_lock);
    707 }
    708 
    709 static int
    710 filt_puffsioctl(struct knote *kn, long hint)
    711 {
    712 	struct puffs_instance *pi = kn->kn_hook;
    713 	struct puffs_mount *pmp;
    714 	int error;
    715 
    716 	error = 0;
    717 	simple_lock(&pi_lock);
    718 	pmp = pi->pi_pmp;
    719 	if (pmp == PMP_EMBRYO || pmp == PMP_DEAD)
    720 		error = 1;
    721 	simple_unlock(&pi_lock);
    722 	if (error)
    723 		return 0;
    724 
    725 	simple_lock(&pmp->pmp_lock);
    726 	kn->kn_data = pmp->pmp_req_touser_waiters;
    727 	simple_unlock(&pmp->pmp_lock);
    728 
    729 	return kn->kn_data != 0;
    730 }
    731 
    732 static const struct filterops puffsioctl_filtops =
    733 	{ 1, NULL, filt_puffsdetach, filt_puffsioctl };
    734 
    735 static int
    736 puffs_fop_kqfilter(struct file *fp, struct knote *kn)
    737 {
    738 	struct puffs_instance *pi = fp->f_data;
    739 	struct klist *klist;
    740 
    741 	if (kn->kn_filter != EVFILT_READ)
    742 		return 1;
    743 
    744 	klist = &pi->pi_sel.sel_klist;
    745 	kn->kn_fop = &puffsioctl_filtops;
    746 	kn->kn_hook = pi;
    747 
    748 	simple_lock(&pi_lock);
    749 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
    750 	simple_unlock(&pi_lock);
    751 
    752 	return 0;
    753 }
    754 
    755 /*
    756  * ioctl handlers
    757  */
    758 
    759 static int
    760 puffsgetop(struct puffs_mount *pmp, struct puffs_req *preq, int nonblock)
    761 {
    762 	struct puffs_park *park;
    763 	int error;
    764 
    765 	simple_lock(&pmp->pmp_lock);
    766  again:
    767 	if (pmp->pmp_status != PUFFSTAT_RUNNING) {
    768 		simple_unlock(&pmp->pmp_lock);
    769 		return ENXIO;
    770 	}
    771 	if (TAILQ_EMPTY(&pmp->pmp_req_touser)) {
    772 		if (nonblock) {
    773 			simple_unlock(&pmp->pmp_lock);
    774 			return EWOULDBLOCK;
    775 		}
    776 		ltsleep(&pmp->pmp_req_touser, PUSER, "puffs2", 0,
    777 		    &pmp->pmp_lock);
    778 		goto again;
    779 	}
    780 
    781 	park = TAILQ_FIRST(&pmp->pmp_req_touser);
    782 	if (preq->preq_auxlen < park->park_copylen) {
    783 		simple_unlock(&pmp->pmp_lock);
    784 		return E2BIG;
    785 	}
    786 	TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries);
    787 	pmp->pmp_req_touser_waiters--;
    788 	simple_unlock(&pmp->pmp_lock);
    789 
    790 	preq->preq_id = park->park_id;
    791 	preq->preq_opclass = park->park_opclass;
    792 	preq->preq_optype = park->park_optype;
    793 	preq->preq_cookie = park->park_cookie;
    794 	preq->preq_auxlen = park->park_copylen;
    795 
    796 	if ((error = copyout(park->park_kernbuf, preq->preq_aux,
    797 	    park->park_copylen)) != 0) {
    798 		/*
    799 		 * ok, user server is probably trying to cheat.
    800 		 * stuff op back & return error to user
    801 		 */
    802 		 simple_lock(&pmp->pmp_lock);
    803 		 TAILQ_INSERT_HEAD(&pmp->pmp_req_touser, park, park_entries);
    804 		 simple_unlock(&pmp->pmp_lock);
    805 		 return error;
    806 	}
    807 
    808 	if (PUFFSOP_WANTREPLY(park->park_opclass)) {
    809 		simple_lock(&pmp->pmp_lock);
    810 		TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, park_entries);
    811 		simple_unlock(&pmp->pmp_lock);
    812 	} else {
    813 		free(park->park_kernbuf, M_PUFFS);
    814 		free(park, M_PUFFS);
    815 	}
    816 
    817 	return 0;
    818 }
    819 
    820 static int
    821 puffsputop(struct puffs_mount *pmp, struct puffs_req *preq)
    822 {
    823 	struct puffs_park *park;
    824 	size_t copylen;
    825 	int error;
    826 
    827 	simple_lock(&pmp->pmp_lock);
    828 	TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) {
    829 		if (park->park_id == preq->preq_id) {
    830 			TAILQ_REMOVE(&pmp->pmp_req_replywait, park,
    831 			    park_entries);
    832 			break;
    833 		}
    834 	}
    835 	simple_unlock(&pmp->pmp_lock);
    836 
    837 	if (park == NULL)
    838 		return EINVAL;
    839 
    840 	/*
    841 	 * check size of incoming transmission.  allow to allocate a
    842 	 * larger kernel buffer only if it was specified by the caller
    843 	 * by setting preq->preq_auxadj.  Else, just copy whatever the
    844 	 * kernel buffer size is unless.
    845 	 *
    846 	 * However, don't allow ludicrously large buffers
    847 	 */
    848 	copylen = preq->preq_auxlen;
    849 	if (copylen > pmp->pmp_req_maxsize) {
    850 #ifdef DIAGNOSTIC
    851 		printf("puffsputop: outrageous user buf size: %zu\n", copylen);
    852 #endif
    853 		error = EFAULT;
    854 		goto out;
    855 	}
    856 
    857 	if (park->park_buflen < copylen &&
    858 	    park->park_flags & PUFFS_REQFLAG_ADJBUF) {
    859 		free(park->park_kernbuf, M_PUFFS);
    860 		park->park_kernbuf = malloc(copylen, M_PUFFS, M_WAITOK);
    861 		park->park_buflen = copylen;
    862 	}
    863 
    864 	error = copyin(preq->preq_aux, park->park_kernbuf, copylen);
    865 
    866 	/*
    867 	 * if copyin botched, inform both userspace and the vnodeop
    868 	 * desperately waiting for information
    869 	 */
    870  out:
    871 	if (error)
    872 		park->park_rv = error;
    873 	else
    874 		park->park_rv = preq->preq_rv;
    875 	wakeup(park);
    876 
    877 	return error;
    878 }
    879 
    880 /* this is probably going to die away at some point? */
    881 static int
    882 puffssizeop(struct puffs_mount *pmp, struct puffs_sizeop *psop_user)
    883 {
    884 	struct puffs_sizepark *pspark;
    885 	void *kernbuf;
    886 	size_t copylen;
    887 	int error;
    888 
    889 	/* locate correct op */
    890 	simple_lock(&pmp->pmp_lock);
    891 	TAILQ_FOREACH(pspark, &pmp->pmp_req_sizepark, pkso_entries) {
    892 		if (pspark->pkso_reqid == psop_user->pso_reqid) {
    893 			TAILQ_REMOVE(&pmp->pmp_req_sizepark, pspark,
    894 			    pkso_entries);
    895 			break;
    896 		}
    897 	}
    898 	simple_unlock(&pmp->pmp_lock);
    899 
    900 	if (pspark == NULL)
    901 		return EINVAL;
    902 
    903 	error = 0;
    904 	copylen = MIN(pspark->pkso_bufsize, psop_user->pso_bufsize);
    905 
    906 	/*
    907 	 * XXX: uvm stuff to avoid bouncy-bouncy copying?
    908 	 */
    909 	if (PUFFS_SIZEOP_UIO(pspark->pkso_reqtype)) {
    910 		kernbuf = malloc(copylen, M_PUFFS, M_WAITOK | M_ZERO);
    911 		if (pspark->pkso_reqtype == PUFFS_SIZEOPREQ_UIO_IN) {
    912 			error = copyin(psop_user->pso_userbuf,
    913 			    kernbuf, copylen);
    914 			if (error) {
    915 				printf("psop ERROR1 %d\n", error);
    916 				goto escape;
    917 			}
    918 		}
    919 		error = uiomove(kernbuf, copylen, pspark->pkso_uio);
    920 		if (error) {
    921 			printf("uiomove from kernel %p, len %d failed: %d\n",
    922 			    kernbuf, (int)copylen, error);
    923 			goto escape;
    924 		}
    925 
    926 		if (pspark->pkso_reqtype == PUFFS_SIZEOPREQ_UIO_OUT) {
    927 			error = copyout(kernbuf,
    928 			    psop_user->pso_userbuf, copylen);
    929 			if (error) {
    930 				printf("psop ERROR2 %d\n", error);
    931 				goto escape;
    932 			}
    933 		}
    934  escape:
    935 		free(kernbuf, M_PUFFS);
    936 	} else if (PUFFS_SIZEOP_BUF(pspark->pkso_reqtype)) {
    937 		copylen = MAX(pspark->pkso_bufsize, psop_user->pso_bufsize);
    938 		if (pspark->pkso_reqtype == PUFFS_SIZEOPREQ_BUF_IN) {
    939 			error = copyin(psop_user->pso_userbuf,
    940 			pspark->pkso_copybuf, copylen);
    941 		} else {
    942 			error = copyout(pspark->pkso_copybuf,
    943 			    psop_user->pso_userbuf, copylen);
    944 		}
    945 	}
    946 #ifdef DIAGNOSTIC
    947 	else
    948 		panic("puffssizeop: invalid reqtype %d\n",
    949 		    pspark->pkso_reqtype);
    950 #endif /* DIAGNOSTIC */
    951 
    952 	return error;
    953 }
    954