Home | History | Annotate | Line # | Download | only in puffs
puffs_vfsops.c revision 1.13.2.1
      1  1.13.2.1   tron /*	$NetBSD: puffs_vfsops.c,v 1.13.2.1 2007/02/17 23:27:45 tron Exp $	*/
      2       1.1  pooka 
      3       1.1  pooka /*
      4       1.1  pooka  * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
      5       1.1  pooka  *
      6       1.1  pooka  * Development of this software was supported by the
      7       1.1  pooka  * Google Summer of Code program and the Ulla Tuominen Foundation.
      8       1.1  pooka  * The Google SoC project was mentored by Bill Studenmund.
      9       1.1  pooka  *
     10       1.1  pooka  * Redistribution and use in source and binary forms, with or without
     11       1.1  pooka  * modification, are permitted provided that the following conditions
     12       1.1  pooka  * are met:
     13       1.1  pooka  * 1. Redistributions of source code must retain the above copyright
     14       1.1  pooka  *    notice, this list of conditions and the following disclaimer.
     15       1.1  pooka  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  pooka  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  pooka  *    documentation and/or other materials provided with the distribution.
     18       1.1  pooka  * 3. The name of the company nor the name of the author may be used to
     19       1.1  pooka  *    endorse or promote products derived from this software without specific
     20       1.1  pooka  *    prior written permission.
     21       1.1  pooka  *
     22       1.1  pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     23       1.1  pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24       1.1  pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     25       1.1  pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     26       1.1  pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27       1.1  pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     28       1.1  pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29       1.1  pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30       1.1  pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31       1.1  pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32       1.1  pooka  * SUCH DAMAGE.
     33       1.1  pooka  */
     34       1.1  pooka 
     35       1.1  pooka #include <sys/cdefs.h>
     36  1.13.2.1   tron __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.13.2.1 2007/02/17 23:27:45 tron Exp $");
     37       1.1  pooka 
     38       1.1  pooka #include <sys/param.h>
     39       1.1  pooka #include <sys/mount.h>
     40       1.1  pooka #include <sys/malloc.h>
     41       1.1  pooka #include <sys/extattr.h>
     42       1.1  pooka #include <sys/queue.h>
     43       1.1  pooka #include <sys/vnode.h>
     44       1.1  pooka #include <sys/dirent.h>
     45       1.1  pooka #include <sys/kauth.h>
     46       1.1  pooka 
     47       1.1  pooka #include <lib/libkern/libkern.h>
     48       1.1  pooka 
     49       1.1  pooka #include <fs/puffs/puffs_msgif.h>
     50       1.1  pooka #include <fs/puffs/puffs_sys.h>
     51       1.1  pooka 
     52       1.1  pooka VFS_PROTOS(puffs);
     53       1.1  pooka 
     54       1.1  pooka MALLOC_DEFINE(M_PUFFS, "puffs", "pass-to-userspace file system structures");
     55       1.1  pooka 
     56       1.1  pooka int
     57       1.1  pooka puffs_mount(struct mount *mp, const char *path, void *data,
     58       1.1  pooka 	    struct nameidata *ndp, struct lwp *l)
     59       1.1  pooka {
     60       1.1  pooka 	struct puffs_mount *pmp;
     61       1.1  pooka 	struct puffs_args args;
     62       1.1  pooka 	char namebuf[PUFFSNAMESIZE+sizeof("puffs:")+1]; /* do I get a prize? */
     63       1.1  pooka 	int error;
     64       1.1  pooka 
     65       1.1  pooka 	if (mp->mnt_flag & MNT_GETARGS) {
     66       1.1  pooka 		pmp = MPTOPUFFSMP(mp);
     67       1.1  pooka 		return copyout(&pmp->pmp_args, data, sizeof(struct puffs_args));
     68       1.1  pooka 	}
     69       1.1  pooka 
     70       1.1  pooka 	/* update is not supported currently */
     71       1.1  pooka 	if (mp->mnt_flag & MNT_UPDATE)
     72       1.1  pooka 		return EOPNOTSUPP;
     73       1.1  pooka 
     74       1.1  pooka 	/*
     75       1.1  pooka 	 * We need the file system name
     76       1.1  pooka 	 */
     77       1.1  pooka 	if (!data)
     78       1.1  pooka 		return EINVAL;
     79       1.1  pooka 
     80       1.1  pooka 	error = copyin(data, &args, sizeof(struct puffs_args));
     81       1.1  pooka 	if (error)
     82       1.1  pooka 		return error;
     83       1.1  pooka 
     84       1.8  pooka 	/* nuke spy bits */
     85      1.13  pooka 	args.pa_flags &= PUFFS_KFLAG_MASK;
     86       1.8  pooka 
     87       1.1  pooka 	/* build real name */
     88       1.1  pooka 	(void)strlcpy(namebuf, "puffs:", sizeof(namebuf));
     89       1.1  pooka 	(void)strlcat(namebuf, args.pa_name, sizeof(namebuf));
     90       1.1  pooka 
     91       1.1  pooka 	/* inform user server if it got the max request size it wanted */
     92       1.1  pooka 	if (args.pa_maxreqlen == 0 || args.pa_maxreqlen > PUFFS_REQ_MAXSIZE)
     93       1.1  pooka 		args.pa_maxreqlen = PUFFS_REQ_MAXSIZE;
     94       1.1  pooka 	else if (args.pa_maxreqlen < PUFFS_REQSTRUCT_MAX)
     95       1.1  pooka 		args.pa_maxreqlen = PUFFS_REQSTRUCT_MAX;
     96       1.1  pooka 	(void)strlcpy(args.pa_name, namebuf, sizeof(args.pa_name));
     97       1.1  pooka 
     98       1.1  pooka 	error = copyout(&args, data, sizeof(struct puffs_args));
     99       1.1  pooka 	if (error)
    100       1.1  pooka 		return error;
    101       1.1  pooka 
    102       1.1  pooka 	error = set_statvfs_info(path, UIO_USERSPACE, namebuf,
    103       1.1  pooka 	    UIO_SYSSPACE, mp, l);
    104       1.1  pooka 	if (error)
    105       1.1  pooka 		return error;
    106      1.10  pooka 	mp->mnt_stat.f_iosize = DEV_BSIZE;
    107       1.1  pooka 
    108       1.1  pooka 	MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount),
    109       1.1  pooka 	    M_PUFFS, M_WAITOK | M_ZERO);
    110       1.1  pooka 
    111       1.6  pooka 	mp->mnt_fs_bshift = DEV_BSHIFT;
    112       1.6  pooka 	mp->mnt_dev_bshift = DEV_BSHIFT;
    113       1.6  pooka 	mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
    114       1.1  pooka 	mp->mnt_data = pmp;
    115       1.6  pooka 
    116       1.1  pooka 	pmp->pmp_status = PUFFSTAT_MOUNTING;
    117       1.1  pooka 	pmp->pmp_nextreq = 0;
    118       1.1  pooka 	pmp->pmp_mp = mp;
    119       1.1  pooka 	pmp->pmp_req_maxsize = args.pa_maxreqlen;
    120       1.1  pooka 	pmp->pmp_args = args;
    121       1.1  pooka 
    122       1.1  pooka 	/*
    123       1.1  pooka 	 * Inform the fileops processing code that we have a mountpoint.
    124       1.1  pooka 	 * If it doesn't know about anyone with our pid/fd having the
    125       1.1  pooka 	 * device open, punt
    126       1.1  pooka 	 */
    127       1.1  pooka 	if (puffs_setpmp(l->l_proc->p_pid, args.pa_fd, pmp)) {
    128       1.1  pooka 		FREE(pmp, M_PUFFS);
    129       1.1  pooka 		return ENOENT;
    130       1.1  pooka 	}
    131       1.1  pooka 
    132       1.1  pooka 	simple_lock_init(&pmp->pmp_lock);
    133       1.1  pooka 	TAILQ_INIT(&pmp->pmp_req_touser);
    134       1.1  pooka 	TAILQ_INIT(&pmp->pmp_req_replywait);
    135       1.1  pooka 	TAILQ_INIT(&pmp->pmp_req_sizepark);
    136       1.1  pooka 
    137       1.1  pooka 	DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
    138       1.1  pooka 	    mp, MPTOPUFFSMP(mp)));
    139       1.1  pooka 
    140       1.1  pooka 	vfs_getnewfsid(mp);
    141       1.1  pooka 
    142       1.1  pooka 	return 0;
    143       1.1  pooka }
    144       1.1  pooka 
    145       1.1  pooka /*
    146       1.1  pooka  * This is called from the first "Hello, I'm alive" ioctl
    147       1.1  pooka  * from userspace.
    148       1.1  pooka  */
    149       1.1  pooka int
    150       1.7  pooka puffs_start2(struct puffs_mount *pmp, struct puffs_startreq *sreq)
    151       1.1  pooka {
    152       1.1  pooka 	struct puffs_node *pn;
    153       1.1  pooka 	struct mount *mp;
    154       1.1  pooka 
    155       1.1  pooka 	mp = PMPTOMP(pmp);
    156       1.1  pooka 
    157       1.1  pooka 	simple_lock(&pmp->pmp_lock);
    158       1.1  pooka 
    159       1.1  pooka 	/*
    160       1.1  pooka 	 * if someone has issued a VFS_ROOT() already, fill in the
    161       1.1  pooka 	 * vnode cookie.
    162       1.1  pooka 	 */
    163       1.2  pooka 	pn = NULL;
    164       1.1  pooka 	if (pmp->pmp_root) {
    165       1.1  pooka 		pn = VPTOPP(pmp->pmp_root);
    166       1.1  pooka 		pn->pn_cookie = sreq->psr_cookie;
    167       1.1  pooka 	}
    168       1.1  pooka 
    169       1.1  pooka 	/* We're good to fly */
    170       1.1  pooka 	pmp->pmp_rootcookie = sreq->psr_cookie;
    171       1.1  pooka 	pmp->pmp_status = PUFFSTAT_RUNNING;
    172       1.9  pooka 	simple_unlock(&pmp->pmp_lock);
    173       1.1  pooka 
    174       1.9  pooka 	/* do the VFS_STATVFS() we missed out on in sys_mount() */
    175       1.9  pooka 	copy_statvfs_info(&sreq->psr_sb, mp);
    176       1.9  pooka 	(void)memcpy(&mp->mnt_stat, &sreq->psr_sb, sizeof(mp->mnt_stat));
    177      1.11  pooka 	mp->mnt_stat.f_iosize = DEV_BSIZE;
    178       1.1  pooka 
    179       1.2  pooka 	DPRINTF(("puffs_start2: root vp %p, cur root pnode %p, cookie %p\n",
    180       1.1  pooka 	    pmp->pmp_root, pn, sreq->psr_cookie));
    181       1.1  pooka 
    182       1.1  pooka 	return 0;
    183       1.1  pooka }
    184       1.1  pooka 
    185       1.1  pooka int
    186       1.1  pooka puffs_start(struct mount *mp, int flags, struct lwp *l)
    187       1.1  pooka {
    188       1.1  pooka 
    189       1.1  pooka 	/*
    190       1.1  pooka 	 * This cannot travel to userspace, as this is called from
    191       1.1  pooka 	 * the kernel context of the process doing mount(2).  But
    192       1.1  pooka 	 * it's probably a safe bet that the process doing mount(2)
    193       1.1  pooka 	 * realizes it needs to start the filesystem also...
    194       1.1  pooka 	 */
    195       1.1  pooka 	return 0;
    196       1.1  pooka }
    197       1.1  pooka 
    198       1.1  pooka int
    199       1.1  pooka puffs_unmount(struct mount *mp, int mntflags, struct lwp *l)
    200       1.1  pooka {
    201       1.1  pooka 	struct puffs_mount *pmp;
    202       1.1  pooka 	int error, force;
    203       1.1  pooka 
    204       1.1  pooka 	PUFFS_VFSREQ(unmount);
    205       1.1  pooka 
    206       1.1  pooka 	error = 0;
    207       1.1  pooka 	force = mntflags & MNT_FORCE;
    208       1.1  pooka 	pmp = MPTOPUFFSMP(mp);
    209       1.1  pooka 
    210       1.1  pooka 	DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
    211       1.1  pooka 	    "status 0x%x\n", pmp->pmp_status));
    212       1.1  pooka 
    213       1.1  pooka 	/*
    214       1.1  pooka 	 * flush all the vnodes.  VOP_RECLAIM() takes care that the
    215       1.1  pooka 	 * root vnode does not get flushed until unmount.  The
    216       1.1  pooka 	 * userspace root node cookie is stored in the mount
    217       1.1  pooka 	 * structure, so we can always re-instantiate a root vnode,
    218       1.1  pooka 	 * should userspace unmount decide it doesn't want to
    219       1.1  pooka 	 * cooperate.
    220       1.1  pooka 	 */
    221       1.1  pooka 	error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
    222       1.1  pooka 	if (error)
    223       1.1  pooka 		goto out;
    224       1.1  pooka 
    225       1.1  pooka 	/*
    226       1.1  pooka 	 * If we are not DYING, we should ask userspace's opinion
    227       1.1  pooka 	 * about the situation
    228       1.1  pooka 	 */
    229       1.1  pooka 	if (pmp->pmp_status != PUFFSTAT_DYING) {
    230       1.1  pooka 		unmount_arg.pvfsr_flags = mntflags;
    231       1.1  pooka 		unmount_arg.pvfsr_pid = puffs_lwp2pid(l);
    232       1.1  pooka 		error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT,
    233       1.1  pooka 		     &unmount_arg, sizeof(unmount_arg));
    234       1.1  pooka 	}
    235       1.1  pooka 
    236       1.1  pooka 	/*
    237       1.1  pooka 	 * if userspace cooperated or we really need to die,
    238       1.1  pooka 	 * screw what userland thinks and just die.
    239       1.1  pooka 	 */
    240       1.2  pooka 	DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
    241       1.1  pooka 	if (error == 0 || force) {
    242       1.1  pooka 		pmp->pmp_status = PUFFSTAT_DYING;
    243       1.1  pooka 		puffs_nukebypmp(pmp);
    244       1.1  pooka 		FREE(pmp, M_PUFFS);
    245       1.1  pooka 		error = 0;
    246       1.1  pooka 	}
    247       1.1  pooka 
    248       1.1  pooka  out:
    249       1.2  pooka 	DPRINTF(("puffs_unmount: return %d\n", error));
    250       1.1  pooka 	return error;
    251       1.1  pooka }
    252       1.1  pooka 
    253       1.1  pooka /*
    254       1.1  pooka  * This doesn't need to travel to userspace
    255       1.1  pooka  */
    256       1.1  pooka int
    257       1.1  pooka puffs_root(struct mount *mp, struct vnode **vpp)
    258       1.1  pooka {
    259       1.1  pooka 	struct puffs_mount *pmp;
    260       1.1  pooka 	struct puffs_node *pn;
    261       1.1  pooka 	struct vnode *vp;
    262       1.1  pooka 
    263       1.1  pooka 	pmp = MPTOPUFFSMP(mp);
    264       1.1  pooka 
    265       1.1  pooka 	/*
    266       1.1  pooka 	 * pmp_lock must be held if vref()'ing or vrele()'ing the
    267       1.1  pooka 	 * root vnode.
    268       1.1  pooka 	 */
    269       1.1  pooka 	simple_lock(&pmp->pmp_lock);
    270       1.1  pooka 	vp = pmp->pmp_root;
    271       1.1  pooka 	if (vp) {
    272       1.1  pooka 		pn = VPTOPP(vp);
    273       1.1  pooka 		if (pn->pn_stat & PNODE_INACTIVE)  {
    274       1.1  pooka 			if (vget(vp, LK_NOWAIT)) {
    275       1.1  pooka 				pmp->pmp_root = NULL;
    276       1.1  pooka 				goto grabnew;
    277       1.1  pooka 			}
    278       1.1  pooka 		} else
    279       1.1  pooka 			vref(vp);
    280       1.1  pooka 		simple_unlock(&pmp->pmp_lock);
    281       1.1  pooka 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    282       1.1  pooka 		*vpp = vp;
    283       1.1  pooka 		return 0;
    284       1.1  pooka 	}
    285       1.1  pooka  grabnew:
    286       1.1  pooka 	simple_unlock(&pmp->pmp_lock);
    287       1.1  pooka 
    288       1.1  pooka 	/*
    289       1.1  pooka 	 * So, didn't have the magic root vnode available.
    290       1.1  pooka 	 * No matter, grab another an stuff it with the cookie.
    291       1.1  pooka 	 */
    292       1.6  pooka 	if (puffs_getvnode(mp, pmp->pmp_rootcookie, VDIR, 0, 0, &vp))
    293       1.1  pooka 		panic("sloppy programming");
    294       1.1  pooka 
    295       1.1  pooka 	simple_lock(&pmp->pmp_lock);
    296       1.1  pooka 	/*
    297       1.1  pooka 	 * check if by mysterious force someone else created a root
    298       1.1  pooka 	 * vnode while we were executing.
    299       1.1  pooka 	 */
    300       1.1  pooka 	if (pmp->pmp_root) {
    301       1.1  pooka 		vref(pmp->pmp_root);
    302       1.1  pooka 		simple_unlock(&pmp->pmp_lock);
    303       1.1  pooka 		puffs_putvnode(vp);
    304       1.1  pooka 		vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
    305       1.1  pooka 		*vpp = pmp->pmp_root;
    306       1.1  pooka 		return 0;
    307       1.1  pooka 	}
    308       1.1  pooka 
    309       1.1  pooka 	/* store cache */
    310       1.1  pooka 	vp->v_flag = VROOT;
    311       1.1  pooka 	pmp->pmp_root = vp;
    312       1.1  pooka 	simple_unlock(&pmp->pmp_lock);
    313       1.1  pooka 
    314       1.1  pooka 	vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
    315       1.1  pooka 
    316       1.1  pooka 	*vpp = vp;
    317       1.1  pooka 	return 0;
    318       1.1  pooka }
    319       1.1  pooka 
    320       1.1  pooka int
    321       1.1  pooka puffs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, struct lwp *l)
    322       1.1  pooka {
    323       1.1  pooka 
    324       1.1  pooka 	return EOPNOTSUPP;
    325       1.1  pooka }
    326       1.1  pooka 
    327       1.1  pooka int
    328       1.1  pooka puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
    329       1.1  pooka {
    330       1.1  pooka 	struct puffs_vfsreq_statvfs *statvfs_arg; /* too big for stack */
    331       1.1  pooka 	struct puffs_mount *pmp;
    332       1.1  pooka 	int error = 0;
    333       1.1  pooka 
    334       1.1  pooka 	pmp = MPTOPUFFSMP(mp);
    335       1.1  pooka 
    336       1.1  pooka 	/*
    337       1.1  pooka 	 * If we are mounting, it means that the userspace counterpart
    338       1.1  pooka 	 * is calling mount(2), but mount(2) also calls statvfs.  So
    339       1.1  pooka 	 * requesting statvfs from userspace would mean a deadlock.
    340       1.1  pooka 	 * Compensate.
    341       1.1  pooka 	 */
    342       1.1  pooka 	if (pmp->pmp_status == PUFFSTAT_MOUNTING)
    343       1.1  pooka 		return EINPROGRESS;
    344       1.1  pooka 
    345       1.1  pooka 	/* too big for stack */
    346       1.1  pooka 	MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *,
    347       1.1  pooka 	    sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO);
    348       1.1  pooka 	statvfs_arg->pvfsr_pid = puffs_lwp2pid(l);
    349       1.1  pooka 
    350       1.1  pooka 	error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS,
    351       1.1  pooka 	    statvfs_arg, sizeof(*statvfs_arg));
    352      1.11  pooka 	statvfs_arg->pvfsr_sb.f_iosize = DEV_BSIZE;
    353      1.10  pooka 
    354       1.1  pooka 	/*
    355       1.1  pooka 	 * Try to produce a sensible result even in the event
    356       1.1  pooka 	 * of userspace error.
    357       1.1  pooka 	 *
    358       1.1  pooka 	 * XXX: cache the copy in non-error case
    359       1.1  pooka 	 */
    360       1.1  pooka 	if (!error) {
    361       1.1  pooka 		copy_statvfs_info(&statvfs_arg->pvfsr_sb, mp);
    362       1.1  pooka 		(void)memcpy(sbp, &statvfs_arg->pvfsr_sb,
    363       1.1  pooka 		    sizeof(struct statvfs));
    364       1.1  pooka 	} else {
    365       1.1  pooka 		copy_statvfs_info(sbp, mp);
    366       1.1  pooka 	}
    367       1.1  pooka 
    368       1.1  pooka 	FREE(statvfs_arg, M_PUFFS);
    369       1.1  pooka 
    370       1.1  pooka 	return 0;
    371       1.1  pooka }
    372       1.1  pooka 
    373       1.1  pooka int
    374       1.1  pooka puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
    375       1.1  pooka 	struct lwp *l)
    376       1.1  pooka {
    377       1.1  pooka 	int error;
    378       1.1  pooka 
    379       1.1  pooka 	PUFFS_VFSREQ(sync);
    380       1.1  pooka 
    381       1.1  pooka 	sync_arg.pvfsr_waitfor = waitfor;
    382       1.1  pooka 	puffs_credcvt(&sync_arg.pvfsr_cred, cred);
    383       1.1  pooka 	sync_arg.pvfsr_pid = puffs_lwp2pid(l);
    384       1.1  pooka 
    385       1.1  pooka 	error = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC,
    386       1.1  pooka 	    &sync_arg, sizeof(sync_arg));
    387       1.1  pooka 
    388       1.1  pooka 	return error;
    389       1.1  pooka }
    390       1.1  pooka 
    391       1.1  pooka int
    392       1.1  pooka puffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
    393       1.1  pooka {
    394       1.1  pooka 
    395       1.1  pooka 	return EOPNOTSUPP;
    396       1.1  pooka }
    397       1.1  pooka 
    398       1.1  pooka #if 0
    399       1.1  pooka /*ARGSUSED*/
    400       1.1  pooka int
    401       1.1  pooka puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
    402       1.1  pooka {
    403       1.1  pooka 
    404       1.1  pooka 	return EOPNOTSUPP;
    405       1.1  pooka }
    406       1.1  pooka 
    407       1.1  pooka /*ARGSUSED*/
    408       1.1  pooka int
    409       1.1  pooka puffs_vptofh(struct vnode *vp, struct fid *fhp)
    410       1.1  pooka {
    411       1.1  pooka 
    412       1.1  pooka 	return EOPNOTSUPP;
    413       1.1  pooka }
    414       1.1  pooka #endif
    415       1.1  pooka 
    416       1.1  pooka void
    417       1.1  pooka puffs_init()
    418       1.1  pooka {
    419       1.1  pooka 
    420       1.5  pooka #ifdef _LKM
    421       1.5  pooka 	malloc_type_attach(M_PUFFS);
    422       1.5  pooka 	pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
    423       1.5  pooka 	    "puffspnpl", &pool_allocator_nointr);
    424       1.5  pooka #endif
    425       1.5  pooka 
    426       1.1  pooka 	return;
    427       1.1  pooka }
    428       1.1  pooka 
    429       1.1  pooka void
    430       1.1  pooka puffs_done()
    431       1.1  pooka {
    432       1.1  pooka 
    433       1.5  pooka #ifdef _LKM
    434       1.5  pooka 	pool_destroy(&puffs_pnpool);
    435       1.5  pooka 	malloc_type_detach(M_PUFFS);
    436       1.5  pooka #endif
    437       1.5  pooka 
    438       1.1  pooka 	return;
    439       1.1  pooka }
    440       1.1  pooka 
    441       1.1  pooka int
    442       1.1  pooka puffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
    443       1.1  pooka {
    444       1.1  pooka 
    445       1.1  pooka 	return EOPNOTSUPP;
    446       1.1  pooka }
    447       1.1  pooka 
    448       1.1  pooka const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
    449       1.1  pooka 	&puffs_vnodeop_opv_desc,
    450       1.3  pooka 	&puffs_specop_opv_desc,
    451       1.4  pooka 	&puffs_fifoop_opv_desc,
    452      1.12  pooka 	&puffs_msgop_opv_desc,
    453       1.1  pooka 	NULL,
    454       1.1  pooka };
    455       1.1  pooka 
    456       1.1  pooka struct vfsops puffs_vfsops = {
    457       1.1  pooka 	MOUNT_PUFFS,
    458       1.1  pooka 	puffs_mount,		/* mount	*/
    459       1.1  pooka 	puffs_start,		/* start	*/
    460       1.1  pooka 	puffs_unmount,		/* unmount	*/
    461       1.1  pooka 	puffs_root,		/* root		*/
    462       1.1  pooka 	puffs_quotactl,		/* quotactl	*/
    463       1.1  pooka 	puffs_statvfs,		/* statvfs	*/
    464       1.1  pooka 	puffs_sync,		/* sync		*/
    465       1.1  pooka 	puffs_vget,		/* vget		*/
    466  1.13.2.1   tron 	(void *)eopnotsupp,	/* fhtovp	*/
    467  1.13.2.1   tron 	(void *)eopnotsupp,	/* vptofh	*/
    468       1.1  pooka 	puffs_init,		/* init		*/
    469       1.1  pooka 	NULL,			/* reinit	*/
    470       1.1  pooka 	puffs_done,		/* done		*/
    471       1.1  pooka 	NULL,			/* mountroot	*/
    472       1.1  pooka 	puffs_snapshot,		/* snapshot	*/
    473       1.1  pooka 	vfs_stdextattrctl,	/* extattrctl	*/
    474       1.1  pooka 	puffs_vnodeopv_descs,	/* vnodeops	*/
    475       1.1  pooka 	0,			/* refcount	*/
    476       1.1  pooka 	{ NULL, NULL }
    477       1.1  pooka };
    478       1.1  pooka VFS_ATTACH(puffs_vfsops);
    479