xref: /minix/sys/fs/puffs/puffs_vfsops.c (revision 0a6a1f1d)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: puffs_vfsops.c,v 1.117 2015/02/16 10:49:39 martin Exp $	*/
284d9c625SLionel Sambuc 
384d9c625SLionel Sambuc /*
484d9c625SLionel Sambuc  * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
584d9c625SLionel Sambuc  *
684d9c625SLionel Sambuc  * Development of this software was supported by the
784d9c625SLionel Sambuc  * Google Summer of Code program and the Ulla Tuominen Foundation.
884d9c625SLionel Sambuc  * The Google SoC project was mentored by Bill Studenmund.
984d9c625SLionel Sambuc  *
1084d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
1184d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions
1284d9c625SLionel Sambuc  * are met:
1384d9c625SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
1484d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
1584d9c625SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
1684d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
1784d9c625SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
1884d9c625SLionel Sambuc  *
1984d9c625SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
2084d9c625SLionel Sambuc  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2184d9c625SLionel Sambuc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2284d9c625SLionel Sambuc  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2384d9c625SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2484d9c625SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2584d9c625SLionel Sambuc  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2684d9c625SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2784d9c625SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2884d9c625SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2984d9c625SLionel Sambuc  * SUCH DAMAGE.
3084d9c625SLionel Sambuc  */
3184d9c625SLionel Sambuc 
3284d9c625SLionel Sambuc #include <sys/cdefs.h>
33*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.117 2015/02/16 10:49:39 martin Exp $");
3484d9c625SLionel Sambuc 
3584d9c625SLionel Sambuc #include <sys/param.h>
3684d9c625SLionel Sambuc #include <sys/kernel.h>
3784d9c625SLionel Sambuc #include <sys/mount.h>
3884d9c625SLionel Sambuc #include <sys/extattr.h>
3984d9c625SLionel Sambuc #include <sys/queue.h>
4084d9c625SLionel Sambuc #include <sys/vnode.h>
4184d9c625SLionel Sambuc #include <sys/dirent.h>
4284d9c625SLionel Sambuc #include <sys/kauth.h>
4384d9c625SLionel Sambuc #include <sys/proc.h>
4484d9c625SLionel Sambuc #include <sys/module.h>
4584d9c625SLionel Sambuc #include <sys/kthread.h>
4684d9c625SLionel Sambuc 
4784d9c625SLionel Sambuc #include <uvm/uvm.h>
4884d9c625SLionel Sambuc 
4984d9c625SLionel Sambuc #include <dev/putter/putter_sys.h>
5084d9c625SLionel Sambuc 
5184d9c625SLionel Sambuc #include <miscfs/genfs/genfs.h>
5284d9c625SLionel Sambuc 
5384d9c625SLionel Sambuc #include <fs/puffs/puffs_msgif.h>
5484d9c625SLionel Sambuc #include <fs/puffs/puffs_sys.h>
5584d9c625SLionel Sambuc 
5684d9c625SLionel Sambuc #include <lib/libkern/libkern.h>
5784d9c625SLionel Sambuc 
5884d9c625SLionel Sambuc #include <nfs/nfsproto.h> /* for fh sizes */
5984d9c625SLionel Sambuc 
6084d9c625SLionel Sambuc MODULE(MODULE_CLASS_VFS, puffs, "putter");
6184d9c625SLionel Sambuc 
6284d9c625SLionel Sambuc VFS_PROTOS(puffs_vfsop);
6384d9c625SLionel Sambuc 
6484d9c625SLionel Sambuc static struct putter_ops puffs_putter = {
6584d9c625SLionel Sambuc 	.pop_getout	= puffs_msgif_getout,
6684d9c625SLionel Sambuc 	.pop_releaseout	= puffs_msgif_releaseout,
6784d9c625SLionel Sambuc 	.pop_waitcount	= puffs_msgif_waitcount,
6884d9c625SLionel Sambuc 	.pop_dispatch	= puffs_msgif_dispatch,
6984d9c625SLionel Sambuc 	.pop_close	= puffs_msgif_close,
7084d9c625SLionel Sambuc };
7184d9c625SLionel Sambuc 
72*0a6a1f1dSLionel Sambuc static const struct genfs_ops puffs_genfsops = {
73*0a6a1f1dSLionel Sambuc         .gop_size = puffs_gop_size,
74*0a6a1f1dSLionel Sambuc 	.gop_write = genfs_gop_write,
75*0a6a1f1dSLionel Sambuc 	.gop_markupdate = puffs_gop_markupdate,
76*0a6a1f1dSLionel Sambuc #if 0
77*0a6a1f1dSLionel Sambuc 	.gop_alloc, should ask userspace
78*0a6a1f1dSLionel Sambuc #endif
79*0a6a1f1dSLionel Sambuc };
80*0a6a1f1dSLionel Sambuc 
8184d9c625SLionel Sambuc /*
8284d9c625SLionel Sambuc  * Try to ensure data structures used by the puffs protocol
8384d9c625SLionel Sambuc  * do not unexpectedly change.
8484d9c625SLionel Sambuc  */
8584d9c625SLionel Sambuc #if defined(__i386__) && defined(__ELF__)
8684d9c625SLionel Sambuc CTASSERT(sizeof(struct puffs_kargs) == 3928);
8784d9c625SLionel Sambuc CTASSERT(sizeof(struct vattr) == 136);
8884d9c625SLionel Sambuc CTASSERT(sizeof(struct puffs_req) == 44);
8984d9c625SLionel Sambuc #endif
9084d9c625SLionel Sambuc 
9184d9c625SLionel Sambuc int
puffs_vfsop_mount(struct mount * mp,const char * path,void * data,size_t * data_len)9284d9c625SLionel Sambuc puffs_vfsop_mount(struct mount *mp, const char *path, void *data,
9384d9c625SLionel Sambuc 	size_t *data_len)
9484d9c625SLionel Sambuc {
9584d9c625SLionel Sambuc 	struct puffs_mount *pmp = NULL;
9684d9c625SLionel Sambuc 	struct puffs_kargs *args;
9784d9c625SLionel Sambuc 	char fstype[_VFS_NAMELEN];
9884d9c625SLionel Sambuc 	char *p;
9984d9c625SLionel Sambuc 	int error = 0, i;
10084d9c625SLionel Sambuc 	pid_t mntpid = curlwp->l_proc->p_pid;
10184d9c625SLionel Sambuc 
102*0a6a1f1dSLionel Sambuc 	if (data == NULL)
103*0a6a1f1dSLionel Sambuc 		return EINVAL;
10484d9c625SLionel Sambuc 	if (*data_len < sizeof *args)
10584d9c625SLionel Sambuc 		return EINVAL;
10684d9c625SLionel Sambuc 
10784d9c625SLionel Sambuc 	if (mp->mnt_flag & MNT_GETARGS) {
10884d9c625SLionel Sambuc 		pmp = MPTOPUFFSMP(mp);
10984d9c625SLionel Sambuc 		*(struct puffs_kargs *)data = pmp->pmp_args;
11084d9c625SLionel Sambuc 		*data_len = sizeof *args;
11184d9c625SLionel Sambuc 		return 0;
11284d9c625SLionel Sambuc 	}
11384d9c625SLionel Sambuc 
11484d9c625SLionel Sambuc 	/* update is not supported currently */
11584d9c625SLionel Sambuc 	if (mp->mnt_flag & MNT_UPDATE)
11684d9c625SLionel Sambuc 		return EOPNOTSUPP;
11784d9c625SLionel Sambuc 
11884d9c625SLionel Sambuc 	args = (struct puffs_kargs *)data;
11984d9c625SLionel Sambuc 
12084d9c625SLionel Sambuc 	if (args->pa_vers != PUFFSVERSION) {
12184d9c625SLionel Sambuc 		printf("puffs_mount: development version mismatch: "
12284d9c625SLionel Sambuc 		    "kernel %d, lib %d\n", PUFFSVERSION, args->pa_vers);
12384d9c625SLionel Sambuc 		error = EINVAL;
12484d9c625SLionel Sambuc 		goto out;
12584d9c625SLionel Sambuc 	}
12684d9c625SLionel Sambuc 
12784d9c625SLionel Sambuc 	if ((args->pa_flags & ~PUFFS_KFLAG_MASK) != 0) {
12884d9c625SLionel Sambuc 		printf("puffs_mount: invalid KFLAGs 0x%x\n", args->pa_flags);
12984d9c625SLionel Sambuc 		error = EINVAL;
13084d9c625SLionel Sambuc 		goto out;
13184d9c625SLionel Sambuc 	}
13284d9c625SLionel Sambuc 	if ((args->pa_fhflags & ~PUFFS_FHFLAG_MASK) != 0) {
13384d9c625SLionel Sambuc 		printf("puffs_mount: invalid FHFLAGs 0x%x\n", args->pa_fhflags);
13484d9c625SLionel Sambuc 		error = EINVAL;
13584d9c625SLionel Sambuc 		goto out;
13684d9c625SLionel Sambuc 	}
13784d9c625SLionel Sambuc 
13884d9c625SLionel Sambuc 	for (i = 0; i < __arraycount(args->pa_spare); i++) {
13984d9c625SLionel Sambuc 		if (args->pa_spare[i] != 0) {
14084d9c625SLionel Sambuc 			printf("puffs_mount: pa_spare[%d] = 0x%x\n",
14184d9c625SLionel Sambuc 			    i, args->pa_spare[i]);
14284d9c625SLionel Sambuc 			error = EINVAL;
14384d9c625SLionel Sambuc 			goto out;
14484d9c625SLionel Sambuc 		}
14584d9c625SLionel Sambuc 	}
14684d9c625SLionel Sambuc 
14784d9c625SLionel Sambuc 	/* use dummy value for passthrough */
14884d9c625SLionel Sambuc 	if (args->pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
14984d9c625SLionel Sambuc 		args->pa_fhsize = sizeof(struct fid);
15084d9c625SLionel Sambuc 
15184d9c625SLionel Sambuc 	/* sanitize file handle length */
15284d9c625SLionel Sambuc 	if (PUFFS_TOFHSIZE(args->pa_fhsize) > FHANDLE_SIZE_MAX) {
15384d9c625SLionel Sambuc 		printf("puffs_mount: handle size %zu too large\n",
15484d9c625SLionel Sambuc 		    args->pa_fhsize);
15584d9c625SLionel Sambuc 		error = EINVAL;
15684d9c625SLionel Sambuc 		goto out;
15784d9c625SLionel Sambuc 	}
15884d9c625SLionel Sambuc 	/* sanity check file handle max sizes */
15984d9c625SLionel Sambuc 	if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) {
16084d9c625SLionel Sambuc 		size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize);
16184d9c625SLionel Sambuc 
16284d9c625SLionel Sambuc 		if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) {
16384d9c625SLionel Sambuc 			if (NFSX_FHTOOBIG_P(kfhsize, 0)) {
16484d9c625SLionel Sambuc 				printf("puffs_mount: fhsize larger than "
16584d9c625SLionel Sambuc 				    "NFSv2 max %d\n",
16684d9c625SLionel Sambuc 				    PUFFS_FROMFHSIZE(NFSX_V2FH));
16784d9c625SLionel Sambuc 				error = EINVAL;
16884d9c625SLionel Sambuc 				goto out;
16984d9c625SLionel Sambuc 			}
17084d9c625SLionel Sambuc 		}
17184d9c625SLionel Sambuc 
17284d9c625SLionel Sambuc 		if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) {
17384d9c625SLionel Sambuc 			if (NFSX_FHTOOBIG_P(kfhsize, 1)) {
17484d9c625SLionel Sambuc 				printf("puffs_mount: fhsize larger than "
17584d9c625SLionel Sambuc 				    "NFSv3 max %d\n",
17684d9c625SLionel Sambuc 				    PUFFS_FROMFHSIZE(NFSX_V3FHMAX));
17784d9c625SLionel Sambuc 				error = EINVAL;
17884d9c625SLionel Sambuc 				goto out;
17984d9c625SLionel Sambuc 			}
18084d9c625SLionel Sambuc 		}
18184d9c625SLionel Sambuc 	}
18284d9c625SLionel Sambuc 
18384d9c625SLionel Sambuc 	/* don't allow non-printing characters (like my sweet umlauts.. snif) */
18484d9c625SLionel Sambuc 	args->pa_typename[sizeof(args->pa_typename)-1] = '\0';
18584d9c625SLionel Sambuc 	for (p = args->pa_typename; *p; p++)
18684d9c625SLionel Sambuc 		if (*p < ' ' || *p > '~')
18784d9c625SLionel Sambuc 			*p = '.';
18884d9c625SLionel Sambuc 
18984d9c625SLionel Sambuc 	args->pa_mntfromname[sizeof(args->pa_mntfromname)-1] = '\0';
19084d9c625SLionel Sambuc 	for (p = args->pa_mntfromname; *p; p++)
19184d9c625SLionel Sambuc 		if (*p < ' ' || *p > '~')
19284d9c625SLionel Sambuc 			*p = '.';
19384d9c625SLionel Sambuc 
19484d9c625SLionel Sambuc 	/* build real name */
19584d9c625SLionel Sambuc 	(void)strlcpy(fstype, PUFFS_TYPEPREFIX, sizeof(fstype));
19684d9c625SLionel Sambuc 	(void)strlcat(fstype, args->pa_typename, sizeof(fstype));
19784d9c625SLionel Sambuc 
19884d9c625SLionel Sambuc 	/* inform user server if it got the max request size it wanted */
19984d9c625SLionel Sambuc 	if (args->pa_maxmsglen == 0 || args->pa_maxmsglen > PUFFS_MSG_MAXSIZE)
20084d9c625SLionel Sambuc 		args->pa_maxmsglen = PUFFS_MSG_MAXSIZE;
20184d9c625SLionel Sambuc 	else if (args->pa_maxmsglen < 2*PUFFS_MSGSTRUCT_MAX)
20284d9c625SLionel Sambuc 		args->pa_maxmsglen = 2*PUFFS_MSGSTRUCT_MAX;
20384d9c625SLionel Sambuc 
20484d9c625SLionel Sambuc 	(void)strlcpy(args->pa_typename, fstype, sizeof(args->pa_typename));
20584d9c625SLionel Sambuc 
20684d9c625SLionel Sambuc 	error = set_statvfs_info(path, UIO_USERSPACE, args->pa_mntfromname,
20784d9c625SLionel Sambuc 	    UIO_SYSSPACE, fstype, mp, curlwp);
20884d9c625SLionel Sambuc 	if (error)
20984d9c625SLionel Sambuc 		goto out;
21084d9c625SLionel Sambuc 	mp->mnt_stat.f_iosize = DEV_BSIZE;
21184d9c625SLionel Sambuc 	mp->mnt_stat.f_namemax = args->pa_svfsb.f_namemax;
21284d9c625SLionel Sambuc 
21384d9c625SLionel Sambuc 	/*
21484d9c625SLionel Sambuc 	 * We can't handle the VFS_STATVFS() mount_domount() does
21584d9c625SLionel Sambuc 	 * after VFS_MOUNT() because we'd deadlock, so handle it
21684d9c625SLionel Sambuc 	 * here already.
21784d9c625SLionel Sambuc 	 */
21884d9c625SLionel Sambuc 	copy_statvfs_info(&args->pa_svfsb, mp);
21984d9c625SLionel Sambuc 	(void)memcpy(&mp->mnt_stat, &args->pa_svfsb, sizeof(mp->mnt_stat));
22084d9c625SLionel Sambuc 
22184d9c625SLionel Sambuc 	KASSERT(curlwp != uvm.pagedaemon_lwp);
22284d9c625SLionel Sambuc 	pmp = kmem_zalloc(sizeof(struct puffs_mount), KM_SLEEP);
22384d9c625SLionel Sambuc 
22484d9c625SLionel Sambuc 	mp->mnt_fs_bshift = DEV_BSHIFT;
22584d9c625SLionel Sambuc 	mp->mnt_dev_bshift = DEV_BSHIFT;
22684d9c625SLionel Sambuc 	mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
22784d9c625SLionel Sambuc 	mp->mnt_data = pmp;
22884d9c625SLionel Sambuc 
22984d9c625SLionel Sambuc #if 0
23084d9c625SLionel Sambuc 	/*
23184d9c625SLionel Sambuc 	 * XXX: puffs code is MPSAFE.  However, VFS really isn't.
23284d9c625SLionel Sambuc 	 * Currently, there is nothing which protects an inode from
23384d9c625SLionel Sambuc 	 * reclaim while there are threads inside the file system.
23484d9c625SLionel Sambuc 	 * This means that in the event of a server crash, an MPSAFE
23584d9c625SLionel Sambuc 	 * mount is likely to end up accessing invalid memory.  For the
23684d9c625SLionel Sambuc 	 * non-mpsafe case, the kernel lock, general structure of
23784d9c625SLionel Sambuc 	 * puffs and pmp_refcount protect the threads during escape.
23884d9c625SLionel Sambuc 	 *
23984d9c625SLionel Sambuc 	 * Fixing this will require:
24084d9c625SLionel Sambuc 	 *  a) fixing vfs
24184d9c625SLionel Sambuc 	 * OR
24284d9c625SLionel Sambuc 	 *  b) adding a small sleep to puffs_msgif_close() between
24384d9c625SLionel Sambuc 	 *     userdead() and dounmount().
24484d9c625SLionel Sambuc 	 *     (well, this isn't really a fix, but would solve
24584d9c625SLionel Sambuc 	 *     99.999% of the race conditions).
24684d9c625SLionel Sambuc 	 *
24784d9c625SLionel Sambuc 	 * Also, in the event of "b", unmount -f should be used,
24884d9c625SLionel Sambuc 	 * like with any other file system, sparingly and only when
24984d9c625SLionel Sambuc 	 * it is "known" to be safe.
25084d9c625SLionel Sambuc 	 */
25184d9c625SLionel Sambuc 	mp->mnt_iflags |= IMNT_MPSAFE;
25284d9c625SLionel Sambuc #endif
25384d9c625SLionel Sambuc 
25484d9c625SLionel Sambuc 	pmp->pmp_status = PUFFSTAT_MOUNTING;
25584d9c625SLionel Sambuc 	pmp->pmp_mp = mp;
25684d9c625SLionel Sambuc 	pmp->pmp_msg_maxsize = args->pa_maxmsglen;
25784d9c625SLionel Sambuc 	pmp->pmp_args = *args;
25884d9c625SLionel Sambuc 
25984d9c625SLionel Sambuc 	/*
26084d9c625SLionel Sambuc 	 * Inform the fileops processing code that we have a mountpoint.
26184d9c625SLionel Sambuc 	 * If it doesn't know about anyone with our pid/fd having the
26284d9c625SLionel Sambuc 	 * device open, punt
26384d9c625SLionel Sambuc 	 */
26484d9c625SLionel Sambuc 	if ((pmp->pmp_pi
26584d9c625SLionel Sambuc 	    = putter_attach(mntpid, args->pa_fd, pmp, &puffs_putter)) == NULL) {
26684d9c625SLionel Sambuc 		error = ENOENT;
26784d9c625SLionel Sambuc 		goto out;
26884d9c625SLionel Sambuc 	}
26984d9c625SLionel Sambuc 
27084d9c625SLionel Sambuc 	/* XXX: check parameters */
27184d9c625SLionel Sambuc 	pmp->pmp_root_cookie = args->pa_root_cookie;
27284d9c625SLionel Sambuc 	pmp->pmp_root_vtype = args->pa_root_vtype;
27384d9c625SLionel Sambuc 	pmp->pmp_root_vsize = args->pa_root_vsize;
27484d9c625SLionel Sambuc 	pmp->pmp_root_rdev = args->pa_root_rdev;
27584d9c625SLionel Sambuc 	pmp->pmp_docompat = args->pa_time32;
27684d9c625SLionel Sambuc 
27784d9c625SLionel Sambuc 	mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE);
27884d9c625SLionel Sambuc 	mutex_init(&pmp->pmp_sopmtx, MUTEX_DEFAULT, IPL_NONE);
27984d9c625SLionel Sambuc 	cv_init(&pmp->pmp_msg_waiter_cv, "puffsget");
28084d9c625SLionel Sambuc 	cv_init(&pmp->pmp_refcount_cv, "puffsref");
28184d9c625SLionel Sambuc 	cv_init(&pmp->pmp_unmounting_cv, "puffsum");
28284d9c625SLionel Sambuc 	cv_init(&pmp->pmp_sopcv, "puffsop");
28384d9c625SLionel Sambuc 	TAILQ_INIT(&pmp->pmp_msg_touser);
28484d9c625SLionel Sambuc 	TAILQ_INIT(&pmp->pmp_msg_replywait);
28584d9c625SLionel Sambuc 	TAILQ_INIT(&pmp->pmp_sopfastreqs);
28684d9c625SLionel Sambuc 	TAILQ_INIT(&pmp->pmp_sopnodereqs);
28784d9c625SLionel Sambuc 
28884d9c625SLionel Sambuc 	if ((error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
28984d9c625SLionel Sambuc 	    puffs_sop_thread, pmp, NULL, "puffsop")) != 0)
29084d9c625SLionel Sambuc 		goto out;
29184d9c625SLionel Sambuc 	pmp->pmp_sopthrcount = 1;
29284d9c625SLionel Sambuc 
29384d9c625SLionel Sambuc 	DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
29484d9c625SLionel Sambuc 	    mp, MPTOPUFFSMP(mp)));
29584d9c625SLionel Sambuc 
29684d9c625SLionel Sambuc 	vfs_getnewfsid(mp);
29784d9c625SLionel Sambuc 
29884d9c625SLionel Sambuc  out:
29984d9c625SLionel Sambuc 	if (error && pmp && pmp->pmp_pi)
30084d9c625SLionel Sambuc 		putter_detach(pmp->pmp_pi);
30184d9c625SLionel Sambuc 	if (error && pmp)
30284d9c625SLionel Sambuc 		kmem_free(pmp, sizeof(struct puffs_mount));
30384d9c625SLionel Sambuc 	return error;
30484d9c625SLionel Sambuc }
30584d9c625SLionel Sambuc 
30684d9c625SLionel Sambuc int
puffs_vfsop_start(struct mount * mp,int flags)30784d9c625SLionel Sambuc puffs_vfsop_start(struct mount *mp, int flags)
30884d9c625SLionel Sambuc {
30984d9c625SLionel Sambuc 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
31084d9c625SLionel Sambuc 
31184d9c625SLionel Sambuc 	KASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING);
31284d9c625SLionel Sambuc 	pmp->pmp_status = PUFFSTAT_RUNNING;
31384d9c625SLionel Sambuc 
31484d9c625SLionel Sambuc 	return 0;
31584d9c625SLionel Sambuc }
31684d9c625SLionel Sambuc 
31784d9c625SLionel Sambuc int
puffs_vfsop_unmount(struct mount * mp,int mntflags)31884d9c625SLionel Sambuc puffs_vfsop_unmount(struct mount *mp, int mntflags)
31984d9c625SLionel Sambuc {
32084d9c625SLionel Sambuc 	PUFFS_MSG_VARS(vfs, unmount);
32184d9c625SLionel Sambuc 	struct puffs_mount *pmp;
32284d9c625SLionel Sambuc 	int error, force;
32384d9c625SLionel Sambuc 
32484d9c625SLionel Sambuc 	error = 0;
32584d9c625SLionel Sambuc 	force = mntflags & MNT_FORCE;
32684d9c625SLionel Sambuc 	pmp = MPTOPUFFSMP(mp);
32784d9c625SLionel Sambuc 
32884d9c625SLionel Sambuc 	DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
32984d9c625SLionel Sambuc 	    "status 0x%x\n", pmp->pmp_status));
33084d9c625SLionel Sambuc 
33184d9c625SLionel Sambuc 	/*
33284d9c625SLionel Sambuc 	 * flush all the vnodes.  VOP_RECLAIM() takes care that the
33384d9c625SLionel Sambuc 	 * root vnode does not get flushed until unmount.  The
33484d9c625SLionel Sambuc 	 * userspace root node cookie is stored in the mount
33584d9c625SLionel Sambuc 	 * structure, so we can always re-instantiate a root vnode,
33684d9c625SLionel Sambuc 	 * should userspace unmount decide it doesn't want to
33784d9c625SLionel Sambuc 	 * cooperate.
33884d9c625SLionel Sambuc 	 */
33984d9c625SLionel Sambuc 	error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
34084d9c625SLionel Sambuc 	if (error)
34184d9c625SLionel Sambuc 		goto out;
34284d9c625SLionel Sambuc 
34384d9c625SLionel Sambuc 	/*
34484d9c625SLionel Sambuc 	 * If we are not DYING, we should ask userspace's opinion
34584d9c625SLionel Sambuc 	 * about the situation
34684d9c625SLionel Sambuc 	 */
34784d9c625SLionel Sambuc 	mutex_enter(&pmp->pmp_lock);
34884d9c625SLionel Sambuc 	if (pmp->pmp_status != PUFFSTAT_DYING) {
34984d9c625SLionel Sambuc 		pmp->pmp_unmounting = 1;
35084d9c625SLionel Sambuc 		mutex_exit(&pmp->pmp_lock);
35184d9c625SLionel Sambuc 
35284d9c625SLionel Sambuc 		PUFFS_MSG_ALLOC(vfs, unmount);
35384d9c625SLionel Sambuc 		puffs_msg_setinfo(park_unmount,
35484d9c625SLionel Sambuc 		    PUFFSOP_VFS, PUFFS_VFS_UNMOUNT, NULL);
35584d9c625SLionel Sambuc 		unmount_msg->pvfsr_flags = mntflags;
35684d9c625SLionel Sambuc 
35784d9c625SLionel Sambuc 		PUFFS_MSG_ENQUEUEWAIT(pmp, park_unmount, error);
35884d9c625SLionel Sambuc 		PUFFS_MSG_RELEASE(unmount);
35984d9c625SLionel Sambuc 
36084d9c625SLionel Sambuc 		error = checkerr(pmp, error, __func__);
36184d9c625SLionel Sambuc 		DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
36284d9c625SLionel Sambuc 
36384d9c625SLionel Sambuc 		mutex_enter(&pmp->pmp_lock);
36484d9c625SLionel Sambuc 		pmp->pmp_unmounting = 0;
36584d9c625SLionel Sambuc 		cv_broadcast(&pmp->pmp_unmounting_cv);
36684d9c625SLionel Sambuc 	}
36784d9c625SLionel Sambuc 
36884d9c625SLionel Sambuc 	/*
36984d9c625SLionel Sambuc 	 * if userspace cooperated or we really need to die,
37084d9c625SLionel Sambuc 	 * screw what userland thinks and just die.
37184d9c625SLionel Sambuc 	 */
37284d9c625SLionel Sambuc 	if (error == 0 || force) {
37384d9c625SLionel Sambuc 		struct puffs_sopreq *psopr;
37484d9c625SLionel Sambuc 
37584d9c625SLionel Sambuc 		/* tell waiters & other resources to go unwait themselves */
37684d9c625SLionel Sambuc 		puffs_userdead(pmp);
37784d9c625SLionel Sambuc 		putter_detach(pmp->pmp_pi);
37884d9c625SLionel Sambuc 
37984d9c625SLionel Sambuc 		/*
38084d9c625SLionel Sambuc 		 * Wait until there are no more users for the mount resource.
38184d9c625SLionel Sambuc 		 * Notice that this is hooked against transport_close
38284d9c625SLionel Sambuc 		 * and return from touser.  In an ideal world, it would
38384d9c625SLionel Sambuc 		 * be hooked against final return from all operations.
38484d9c625SLionel Sambuc 		 * But currently it works well enough, since nobody
38584d9c625SLionel Sambuc 		 * does weird blocking voodoo after return from touser().
38684d9c625SLionel Sambuc 		 */
38784d9c625SLionel Sambuc 		while (pmp->pmp_refcount != 0)
38884d9c625SLionel Sambuc 			cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock);
38984d9c625SLionel Sambuc 		mutex_exit(&pmp->pmp_lock);
39084d9c625SLionel Sambuc 
39184d9c625SLionel Sambuc 		/*
39284d9c625SLionel Sambuc 		 * Release kernel thread now that there is nothing
39384d9c625SLionel Sambuc 		 * it would be wanting to lock.
39484d9c625SLionel Sambuc 		 */
39584d9c625SLionel Sambuc 		KASSERT(curlwp != uvm.pagedaemon_lwp);
39684d9c625SLionel Sambuc 		psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
39784d9c625SLionel Sambuc 		psopr->psopr_sopreq = PUFFS_SOPREQSYS_EXIT;
39884d9c625SLionel Sambuc 		mutex_enter(&pmp->pmp_sopmtx);
39984d9c625SLionel Sambuc 		if (pmp->pmp_sopthrcount == 0) {
40084d9c625SLionel Sambuc 			mutex_exit(&pmp->pmp_sopmtx);
40184d9c625SLionel Sambuc 			kmem_free(psopr, sizeof(*psopr));
40284d9c625SLionel Sambuc 			mutex_enter(&pmp->pmp_sopmtx);
40384d9c625SLionel Sambuc 			KASSERT(pmp->pmp_sopthrcount == 0);
40484d9c625SLionel Sambuc 		} else {
40584d9c625SLionel Sambuc 			TAILQ_INSERT_TAIL(&pmp->pmp_sopfastreqs,
40684d9c625SLionel Sambuc 			    psopr, psopr_entries);
40784d9c625SLionel Sambuc 			cv_signal(&pmp->pmp_sopcv);
40884d9c625SLionel Sambuc 		}
40984d9c625SLionel Sambuc 		while (pmp->pmp_sopthrcount > 0)
41084d9c625SLionel Sambuc 			cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx);
41184d9c625SLionel Sambuc 		mutex_exit(&pmp->pmp_sopmtx);
41284d9c625SLionel Sambuc 
41384d9c625SLionel Sambuc 		/* free resources now that we hopefully have no waiters left */
41484d9c625SLionel Sambuc 		cv_destroy(&pmp->pmp_unmounting_cv);
41584d9c625SLionel Sambuc 		cv_destroy(&pmp->pmp_refcount_cv);
41684d9c625SLionel Sambuc 		cv_destroy(&pmp->pmp_msg_waiter_cv);
41784d9c625SLionel Sambuc 		cv_destroy(&pmp->pmp_sopcv);
41884d9c625SLionel Sambuc 		mutex_destroy(&pmp->pmp_lock);
41984d9c625SLionel Sambuc 		mutex_destroy(&pmp->pmp_sopmtx);
42084d9c625SLionel Sambuc 
42184d9c625SLionel Sambuc 		kmem_free(pmp, sizeof(struct puffs_mount));
42284d9c625SLionel Sambuc 		error = 0;
42384d9c625SLionel Sambuc 	} else {
42484d9c625SLionel Sambuc 		mutex_exit(&pmp->pmp_lock);
42584d9c625SLionel Sambuc 	}
42684d9c625SLionel Sambuc 
42784d9c625SLionel Sambuc  out:
42884d9c625SLionel Sambuc 	DPRINTF(("puffs_unmount: return %d\n", error));
42984d9c625SLionel Sambuc 	return error;
43084d9c625SLionel Sambuc }
43184d9c625SLionel Sambuc 
43284d9c625SLionel Sambuc /*
43384d9c625SLionel Sambuc  * This doesn't need to travel to userspace
43484d9c625SLionel Sambuc  */
43584d9c625SLionel Sambuc int
puffs_vfsop_root(struct mount * mp,struct vnode ** vpp)43684d9c625SLionel Sambuc puffs_vfsop_root(struct mount *mp, struct vnode **vpp)
43784d9c625SLionel Sambuc {
43884d9c625SLionel Sambuc 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
43984d9c625SLionel Sambuc 	int rv;
44084d9c625SLionel Sambuc 
441*0a6a1f1dSLionel Sambuc 	rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, vpp);
44284d9c625SLionel Sambuc 	KASSERT(rv != PUFFS_NOSUCHCOOKIE);
443*0a6a1f1dSLionel Sambuc 	if (rv != 0)
44484d9c625SLionel Sambuc 		return rv;
445*0a6a1f1dSLionel Sambuc 	rv = vn_lock(*vpp, LK_EXCLUSIVE);
446*0a6a1f1dSLionel Sambuc 	if (rv != 0) {
447*0a6a1f1dSLionel Sambuc 		vrele(*vpp);
448*0a6a1f1dSLionel Sambuc 		*vpp = NULL;
449*0a6a1f1dSLionel Sambuc 		return rv;
450*0a6a1f1dSLionel Sambuc 	}
451*0a6a1f1dSLionel Sambuc 	return 0;
45284d9c625SLionel Sambuc }
45384d9c625SLionel Sambuc 
45484d9c625SLionel Sambuc int
puffs_vfsop_statvfs(struct mount * mp,struct statvfs * sbp)45584d9c625SLionel Sambuc puffs_vfsop_statvfs(struct mount *mp, struct statvfs *sbp)
45684d9c625SLionel Sambuc {
45784d9c625SLionel Sambuc 	PUFFS_MSG_VARS(vfs, statvfs);
45884d9c625SLionel Sambuc 	struct puffs_mount *pmp;
45984d9c625SLionel Sambuc 	int error = 0;
46084d9c625SLionel Sambuc 
46184d9c625SLionel Sambuc 	pmp = MPTOPUFFSMP(mp);
46284d9c625SLionel Sambuc 
46384d9c625SLionel Sambuc 	/*
46484d9c625SLionel Sambuc 	 * If we are mounting, it means that the userspace counterpart
46584d9c625SLionel Sambuc 	 * is calling mount(2), but mount(2) also calls statvfs.  So
46684d9c625SLionel Sambuc 	 * requesting statvfs from userspace would mean a deadlock.
46784d9c625SLionel Sambuc 	 * Compensate.
46884d9c625SLionel Sambuc 	 */
46984d9c625SLionel Sambuc 	if (__predict_false(pmp->pmp_status == PUFFSTAT_MOUNTING))
47084d9c625SLionel Sambuc 		return EINPROGRESS;
47184d9c625SLionel Sambuc 
47284d9c625SLionel Sambuc 	PUFFS_MSG_ALLOC(vfs, statvfs);
47384d9c625SLionel Sambuc 	puffs_msg_setinfo(park_statvfs, PUFFSOP_VFS, PUFFS_VFS_STATVFS, NULL);
47484d9c625SLionel Sambuc 
47584d9c625SLionel Sambuc 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_statvfs, error);
47684d9c625SLionel Sambuc 	error = checkerr(pmp, error, __func__);
47784d9c625SLionel Sambuc 	statvfs_msg->pvfsr_sb.f_iosize = DEV_BSIZE;
47884d9c625SLionel Sambuc 
47984d9c625SLionel Sambuc 	/*
48084d9c625SLionel Sambuc 	 * Try to produce a sensible result even in the event
48184d9c625SLionel Sambuc 	 * of userspace error.
48284d9c625SLionel Sambuc 	 *
48384d9c625SLionel Sambuc 	 * XXX: cache the copy in non-error case
48484d9c625SLionel Sambuc 	 */
48584d9c625SLionel Sambuc 	if (!error) {
48684d9c625SLionel Sambuc 		copy_statvfs_info(&statvfs_msg->pvfsr_sb, mp);
48784d9c625SLionel Sambuc 		(void)memcpy(sbp, &statvfs_msg->pvfsr_sb,
48884d9c625SLionel Sambuc 		    sizeof(struct statvfs));
48984d9c625SLionel Sambuc 	} else {
49084d9c625SLionel Sambuc 		copy_statvfs_info(sbp, mp);
49184d9c625SLionel Sambuc 	}
49284d9c625SLionel Sambuc 
49384d9c625SLionel Sambuc 	PUFFS_MSG_RELEASE(statvfs);
49484d9c625SLionel Sambuc 	return error;
49584d9c625SLionel Sambuc }
49684d9c625SLionel Sambuc 
497*0a6a1f1dSLionel Sambuc static bool
pageflush_selector(void * cl,struct vnode * vp)498*0a6a1f1dSLionel Sambuc pageflush_selector(void *cl, struct vnode *vp)
499*0a6a1f1dSLionel Sambuc {
500*0a6a1f1dSLionel Sambuc 	return vp->v_type == VREG &&
501*0a6a1f1dSLionel Sambuc 	    !(LIST_EMPTY(&vp->v_dirtyblkhd) && UVM_OBJ_IS_CLEAN(&vp->v_uobj));
502*0a6a1f1dSLionel Sambuc }
503*0a6a1f1dSLionel Sambuc 
50484d9c625SLionel Sambuc static int
pageflush(struct mount * mp,kauth_cred_t cred,int waitfor)50584d9c625SLionel Sambuc pageflush(struct mount *mp, kauth_cred_t cred, int waitfor)
50684d9c625SLionel Sambuc {
50784d9c625SLionel Sambuc 	struct puffs_node *pn;
508*0a6a1f1dSLionel Sambuc 	struct vnode *vp;
509*0a6a1f1dSLionel Sambuc 	struct vnode_iterator *marker;
51084d9c625SLionel Sambuc 	int error, rv, fsyncwait;
51184d9c625SLionel Sambuc 
51284d9c625SLionel Sambuc 	error = 0;
51384d9c625SLionel Sambuc 	fsyncwait = (waitfor == MNT_WAIT) ? FSYNC_WAIT : 0;
51484d9c625SLionel Sambuc 
51584d9c625SLionel Sambuc 	/*
51684d9c625SLionel Sambuc 	 * Sync all cached data from regular vnodes (which are not
51784d9c625SLionel Sambuc 	 * currently locked, see below).  After this we call VFS_SYNC
51884d9c625SLionel Sambuc 	 * for the fs server, which should handle data and metadata for
51984d9c625SLionel Sambuc 	 * all the nodes it knows to exist.
52084d9c625SLionel Sambuc 	 */
521*0a6a1f1dSLionel Sambuc 	vfs_vnode_iterator_init(mp, &marker);
522*0a6a1f1dSLionel Sambuc 	while ((vp = vfs_vnode_iterator_next(marker, pageflush_selector,
523*0a6a1f1dSLionel Sambuc 	    NULL)))
524*0a6a1f1dSLionel Sambuc 	{
52584d9c625SLionel Sambuc 		/*
52684d9c625SLionel Sambuc 		 * Here we try to get a reference to the vnode and to
52784d9c625SLionel Sambuc 		 * lock it.  This is mostly cargo-culted, but I will
52884d9c625SLionel Sambuc 		 * offer an explanation to why I believe this might
52984d9c625SLionel Sambuc 		 * actually do the right thing.
53084d9c625SLionel Sambuc 		 *
53184d9c625SLionel Sambuc 		 * If the vnode is a goner, we quite obviously don't need
53284d9c625SLionel Sambuc 		 * to sync it.
53384d9c625SLionel Sambuc 		 *
53484d9c625SLionel Sambuc 		 * If the vnode was busy, we don't need to sync it because
53584d9c625SLionel Sambuc 		 * this is never called with MNT_WAIT except from
53684d9c625SLionel Sambuc 		 * dounmount(), when we are wait-flushing all the dirty
53784d9c625SLionel Sambuc 		 * vnodes through other routes in any case.  So there,
53884d9c625SLionel Sambuc 		 * sync() doesn't actually sync.  Happy now?
53984d9c625SLionel Sambuc 		 */
540*0a6a1f1dSLionel Sambuc 		error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT);
541*0a6a1f1dSLionel Sambuc 		if (error) {
542*0a6a1f1dSLionel Sambuc 			vrele(vp);
54384d9c625SLionel Sambuc 			continue;
54484d9c625SLionel Sambuc 		}
545*0a6a1f1dSLionel Sambuc 		pn = VPTOPP(vp);
54684d9c625SLionel Sambuc 		/* hmm.. is the FAF thing entirely sensible? */
54784d9c625SLionel Sambuc 		if (waitfor == MNT_LAZY) {
54884d9c625SLionel Sambuc 			mutex_enter(vp->v_interlock);
54984d9c625SLionel Sambuc 			pn->pn_stat |= PNODE_FAF;
55084d9c625SLionel Sambuc 			mutex_exit(vp->v_interlock);
55184d9c625SLionel Sambuc 		}
55284d9c625SLionel Sambuc 		rv = VOP_FSYNC(vp, cred, fsyncwait, 0, 0);
55384d9c625SLionel Sambuc 		if (waitfor == MNT_LAZY) {
55484d9c625SLionel Sambuc 			mutex_enter(vp->v_interlock);
55584d9c625SLionel Sambuc 			pn->pn_stat &= ~PNODE_FAF;
55684d9c625SLionel Sambuc 			mutex_exit(vp->v_interlock);
55784d9c625SLionel Sambuc 		}
55884d9c625SLionel Sambuc 		if (rv)
55984d9c625SLionel Sambuc 			error = rv;
56084d9c625SLionel Sambuc 		vput(vp);
56184d9c625SLionel Sambuc 	}
562*0a6a1f1dSLionel Sambuc 	vfs_vnode_iterator_destroy(marker);
56384d9c625SLionel Sambuc 
56484d9c625SLionel Sambuc 	return error;
56584d9c625SLionel Sambuc }
56684d9c625SLionel Sambuc 
56784d9c625SLionel Sambuc int
puffs_vfsop_sync(struct mount * mp,int waitfor,struct kauth_cred * cred)56884d9c625SLionel Sambuc puffs_vfsop_sync(struct mount *mp, int waitfor, struct kauth_cred *cred)
56984d9c625SLionel Sambuc {
57084d9c625SLionel Sambuc 	PUFFS_MSG_VARS(vfs, sync);
57184d9c625SLionel Sambuc 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
57284d9c625SLionel Sambuc 	int error, rv;
57384d9c625SLionel Sambuc 
57484d9c625SLionel Sambuc 	error = pageflush(mp, cred, waitfor);
57584d9c625SLionel Sambuc 
57684d9c625SLionel Sambuc 	/* sync fs */
57784d9c625SLionel Sambuc 	PUFFS_MSG_ALLOC(vfs, sync);
57884d9c625SLionel Sambuc 	sync_msg->pvfsr_waitfor = waitfor;
57984d9c625SLionel Sambuc 	puffs_credcvt(&sync_msg->pvfsr_cred, cred);
58084d9c625SLionel Sambuc 	puffs_msg_setinfo(park_sync, PUFFSOP_VFS, PUFFS_VFS_SYNC, NULL);
58184d9c625SLionel Sambuc 
58284d9c625SLionel Sambuc 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_sync, rv);
58384d9c625SLionel Sambuc 	rv = checkerr(pmp, rv, __func__);
58484d9c625SLionel Sambuc 	if (rv)
58584d9c625SLionel Sambuc 		error = rv;
58684d9c625SLionel Sambuc 
58784d9c625SLionel Sambuc 	PUFFS_MSG_RELEASE(sync);
58884d9c625SLionel Sambuc 	return error;
58984d9c625SLionel Sambuc }
59084d9c625SLionel Sambuc 
59184d9c625SLionel Sambuc int
puffs_vfsop_fhtovp(struct mount * mp,struct fid * fhp,struct vnode ** vpp)59284d9c625SLionel Sambuc puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
59384d9c625SLionel Sambuc {
59484d9c625SLionel Sambuc 	PUFFS_MSG_VARS(vfs, fhtonode);
59584d9c625SLionel Sambuc 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
59684d9c625SLionel Sambuc 	struct vnode *vp;
59784d9c625SLionel Sambuc 	void *fhdata;
59884d9c625SLionel Sambuc 	size_t argsize, fhlen;
59984d9c625SLionel Sambuc 	int error;
60084d9c625SLionel Sambuc 
60184d9c625SLionel Sambuc 	if (pmp->pmp_args.pa_fhsize == 0)
60284d9c625SLionel Sambuc 		return EOPNOTSUPP;
60384d9c625SLionel Sambuc 
60484d9c625SLionel Sambuc 	if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
60584d9c625SLionel Sambuc 		fhlen = fhp->fid_len;
60684d9c625SLionel Sambuc 		fhdata = fhp;
60784d9c625SLionel Sambuc 	} else {
60884d9c625SLionel Sambuc 		fhlen = PUFFS_FROMFHSIZE(fhp->fid_len);
60984d9c625SLionel Sambuc 		fhdata = fhp->fid_data;
61084d9c625SLionel Sambuc 
61184d9c625SLionel Sambuc 		if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) {
61284d9c625SLionel Sambuc 			if (pmp->pmp_args.pa_fhsize < fhlen)
61384d9c625SLionel Sambuc 				return EINVAL;
61484d9c625SLionel Sambuc 		} else {
61584d9c625SLionel Sambuc 			if (pmp->pmp_args.pa_fhsize != fhlen)
61684d9c625SLionel Sambuc 				return EINVAL;
61784d9c625SLionel Sambuc 		}
61884d9c625SLionel Sambuc 	}
61984d9c625SLionel Sambuc 
62084d9c625SLionel Sambuc 	argsize = sizeof(struct puffs_vfsmsg_fhtonode) + fhlen;
62184d9c625SLionel Sambuc 	puffs_msgmem_alloc(argsize, &park_fhtonode, (void *)&fhtonode_msg, 1);
62284d9c625SLionel Sambuc 	fhtonode_msg->pvfsr_dsize = fhlen;
62384d9c625SLionel Sambuc 	memcpy(fhtonode_msg->pvfsr_data, fhdata, fhlen);
62484d9c625SLionel Sambuc 	puffs_msg_setinfo(park_fhtonode, PUFFSOP_VFS, PUFFS_VFS_FHTOVP, NULL);
62584d9c625SLionel Sambuc 
62684d9c625SLionel Sambuc 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_fhtonode, error);
62784d9c625SLionel Sambuc 	error = checkerr(pmp, error, __func__);
62884d9c625SLionel Sambuc 	if (error)
62984d9c625SLionel Sambuc 		goto out;
63084d9c625SLionel Sambuc 
63184d9c625SLionel Sambuc 	error = puffs_getvnode(mp, fhtonode_msg->pvfsr_fhcookie,
63284d9c625SLionel Sambuc 	    fhtonode_msg->pvfsr_vtype, fhtonode_msg->pvfsr_size,
63384d9c625SLionel Sambuc 	    fhtonode_msg->pvfsr_rdev, &vp);
63484d9c625SLionel Sambuc 	if (error)
63584d9c625SLionel Sambuc 		goto out;
63684d9c625SLionel Sambuc 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
63784d9c625SLionel Sambuc 
63884d9c625SLionel Sambuc 	*vpp = vp;
63984d9c625SLionel Sambuc  out:
64084d9c625SLionel Sambuc 	puffs_msgmem_release(park_fhtonode);
64184d9c625SLionel Sambuc 	return error;
64284d9c625SLionel Sambuc }
64384d9c625SLionel Sambuc 
64484d9c625SLionel Sambuc int
puffs_vfsop_vptofh(struct vnode * vp,struct fid * fhp,size_t * fh_size)64584d9c625SLionel Sambuc puffs_vfsop_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
64684d9c625SLionel Sambuc {
64784d9c625SLionel Sambuc 	PUFFS_MSG_VARS(vfs, nodetofh);
64884d9c625SLionel Sambuc 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
64984d9c625SLionel Sambuc 	size_t argsize, fhlen;
65084d9c625SLionel Sambuc 	int error;
65184d9c625SLionel Sambuc 
65284d9c625SLionel Sambuc 	if (pmp->pmp_args.pa_fhsize == 0)
65384d9c625SLionel Sambuc 		return EOPNOTSUPP;
65484d9c625SLionel Sambuc 
65584d9c625SLionel Sambuc 	/* if file handles are static len, we can test len immediately */
65684d9c625SLionel Sambuc 	if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0)
65784d9c625SLionel Sambuc 	    && ((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) == 0)
65884d9c625SLionel Sambuc 	    && (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) {
65984d9c625SLionel Sambuc 		*fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
66084d9c625SLionel Sambuc 		return E2BIG;
66184d9c625SLionel Sambuc 	}
66284d9c625SLionel Sambuc 
66384d9c625SLionel Sambuc 	if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
66484d9c625SLionel Sambuc 		fhlen = *fh_size;
66584d9c625SLionel Sambuc 	else
66684d9c625SLionel Sambuc 		fhlen = PUFFS_FROMFHSIZE(*fh_size);
66784d9c625SLionel Sambuc 
66884d9c625SLionel Sambuc 	argsize = sizeof(struct puffs_vfsmsg_nodetofh) + fhlen;
66984d9c625SLionel Sambuc 	puffs_msgmem_alloc(argsize, &park_nodetofh, (void *)&nodetofh_msg, 1);
67084d9c625SLionel Sambuc 	nodetofh_msg->pvfsr_fhcookie = VPTOPNC(vp);
67184d9c625SLionel Sambuc 	nodetofh_msg->pvfsr_dsize = fhlen;
67284d9c625SLionel Sambuc 	puffs_msg_setinfo(park_nodetofh, PUFFSOP_VFS, PUFFS_VFS_VPTOFH, NULL);
67384d9c625SLionel Sambuc 
67484d9c625SLionel Sambuc 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_nodetofh, error);
67584d9c625SLionel Sambuc 	error = checkerr(pmp, error, __func__);
67684d9c625SLionel Sambuc 
67784d9c625SLionel Sambuc 	if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH)
67884d9c625SLionel Sambuc 		fhlen = nodetofh_msg->pvfsr_dsize;
67984d9c625SLionel Sambuc 	else if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC)
68084d9c625SLionel Sambuc 		fhlen = PUFFS_TOFHSIZE(nodetofh_msg->pvfsr_dsize);
68184d9c625SLionel Sambuc 	else
68284d9c625SLionel Sambuc 		fhlen = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize);
68384d9c625SLionel Sambuc 
68484d9c625SLionel Sambuc 	if (error) {
68584d9c625SLionel Sambuc 		if (error == E2BIG)
68684d9c625SLionel Sambuc 			*fh_size = fhlen;
68784d9c625SLionel Sambuc 		goto out;
68884d9c625SLionel Sambuc 	}
68984d9c625SLionel Sambuc 
69084d9c625SLionel Sambuc 	if (fhlen > FHANDLE_SIZE_MAX) {
69184d9c625SLionel Sambuc 		puffs_senderr(pmp, PUFFS_ERR_VPTOFH, E2BIG,
69284d9c625SLionel Sambuc 		    "file handle too big", VPTOPNC(vp));
69384d9c625SLionel Sambuc 		error = EPROTO;
69484d9c625SLionel Sambuc 		goto out;
69584d9c625SLionel Sambuc 	}
69684d9c625SLionel Sambuc 
69784d9c625SLionel Sambuc 	if (*fh_size < fhlen) {
69884d9c625SLionel Sambuc 		*fh_size = fhlen;
69984d9c625SLionel Sambuc 		error = E2BIG;
70084d9c625SLionel Sambuc 		goto out;
70184d9c625SLionel Sambuc 	}
70284d9c625SLionel Sambuc 	*fh_size = fhlen;
70384d9c625SLionel Sambuc 
70484d9c625SLionel Sambuc 	if (fhp) {
70584d9c625SLionel Sambuc 		if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) {
70684d9c625SLionel Sambuc 			memcpy(fhp, nodetofh_msg->pvfsr_data, fhlen);
70784d9c625SLionel Sambuc 		} else {
70884d9c625SLionel Sambuc 			fhp->fid_len = *fh_size;
70984d9c625SLionel Sambuc 			memcpy(fhp->fid_data, nodetofh_msg->pvfsr_data,
71084d9c625SLionel Sambuc 			    nodetofh_msg->pvfsr_dsize);
71184d9c625SLionel Sambuc 		}
71284d9c625SLionel Sambuc 	}
71384d9c625SLionel Sambuc 
71484d9c625SLionel Sambuc  out:
71584d9c625SLionel Sambuc 	puffs_msgmem_release(park_nodetofh);
71684d9c625SLionel Sambuc 	return error;
71784d9c625SLionel Sambuc }
71884d9c625SLionel Sambuc 
719*0a6a1f1dSLionel Sambuc int
puffs_vfsop_loadvnode(struct mount * mp,struct vnode * vp,const void * key,size_t key_len,const void ** new_key)720*0a6a1f1dSLionel Sambuc puffs_vfsop_loadvnode(struct mount *mp, struct vnode *vp,
721*0a6a1f1dSLionel Sambuc     const void *key, size_t key_len, const void **new_key)
722*0a6a1f1dSLionel Sambuc {
723*0a6a1f1dSLionel Sambuc 	struct puffs_mount *pmp;
724*0a6a1f1dSLionel Sambuc 	struct puffs_node *pnode;
725*0a6a1f1dSLionel Sambuc 
726*0a6a1f1dSLionel Sambuc 	KASSERT(key_len == sizeof(puffs_cookie_t));
727*0a6a1f1dSLionel Sambuc 
728*0a6a1f1dSLionel Sambuc 	pmp = MPTOPUFFSMP(mp);
729*0a6a1f1dSLionel Sambuc 
730*0a6a1f1dSLionel Sambuc 	/* Allocate and initialize the pnode. */
731*0a6a1f1dSLionel Sambuc 	pnode = pool_get(&puffs_pnpool, PR_WAITOK);
732*0a6a1f1dSLionel Sambuc 	memset(pnode, 0, sizeof(struct puffs_node));
733*0a6a1f1dSLionel Sambuc 
734*0a6a1f1dSLionel Sambuc 	pnode->pn_vp = vp;
735*0a6a1f1dSLionel Sambuc 	memcpy(&pnode->pn_cookie, key, key_len);
736*0a6a1f1dSLionel Sambuc 	pnode->pn_refcount = 1;
737*0a6a1f1dSLionel Sambuc 	mutex_init(&pnode->pn_mtx, MUTEX_DEFAULT, IPL_NONE);
738*0a6a1f1dSLionel Sambuc 	mutex_init(&pnode->pn_sizemtx, MUTEX_DEFAULT, IPL_NONE);
739*0a6a1f1dSLionel Sambuc 	selinit(&pnode->pn_sel);
740*0a6a1f1dSLionel Sambuc 	vp->v_tag = VT_PUFFS;
741*0a6a1f1dSLionel Sambuc 	vp->v_type = VNON;
742*0a6a1f1dSLionel Sambuc 	vp->v_op = puffs_vnodeop_p;
743*0a6a1f1dSLionel Sambuc 	if (pnode->pn_cookie == pmp->pmp_root_cookie)
744*0a6a1f1dSLionel Sambuc 		vp->v_vflag |= VV_ROOT;
745*0a6a1f1dSLionel Sambuc 	vp->v_data = pnode;
746*0a6a1f1dSLionel Sambuc 
747*0a6a1f1dSLionel Sambuc 	genfs_node_init(vp, &puffs_genfsops);
748*0a6a1f1dSLionel Sambuc 	uvm_vnp_setsize(vp, 0);
749*0a6a1f1dSLionel Sambuc 
750*0a6a1f1dSLionel Sambuc 	*new_key = &pnode->pn_cookie;
751*0a6a1f1dSLionel Sambuc 	return 0;
752*0a6a1f1dSLionel Sambuc }
753*0a6a1f1dSLionel Sambuc 
75484d9c625SLionel Sambuc void
puffs_vfsop_init(void)75584d9c625SLionel Sambuc puffs_vfsop_init(void)
75684d9c625SLionel Sambuc {
75784d9c625SLionel Sambuc 
75884d9c625SLionel Sambuc 	/* some checks depend on this */
75984d9c625SLionel Sambuc 	KASSERT(VNOVAL == VSIZENOTSET);
76084d9c625SLionel Sambuc 
76184d9c625SLionel Sambuc 	pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
76284d9c625SLionel Sambuc 	    "puffpnpl", &pool_allocator_nointr, IPL_NONE);
76384d9c625SLionel Sambuc 	pool_init(&puffs_vapool, sizeof(struct vattr), 0, 0, 0,
76484d9c625SLionel Sambuc 	    "puffvapl", &pool_allocator_nointr, IPL_NONE);
76584d9c625SLionel Sambuc 	puffs_msgif_init();
76684d9c625SLionel Sambuc }
76784d9c625SLionel Sambuc 
76884d9c625SLionel Sambuc void
puffs_vfsop_done(void)76984d9c625SLionel Sambuc puffs_vfsop_done(void)
77084d9c625SLionel Sambuc {
77184d9c625SLionel Sambuc 
77284d9c625SLionel Sambuc 	puffs_msgif_destroy();
77384d9c625SLionel Sambuc 	pool_destroy(&puffs_pnpool);
77484d9c625SLionel Sambuc 	pool_destroy(&puffs_vapool);
77584d9c625SLionel Sambuc }
77684d9c625SLionel Sambuc 
77784d9c625SLionel Sambuc int
puffs_vfsop_snapshot(struct mount * mp,struct vnode * vp,struct timespec * ts)77884d9c625SLionel Sambuc puffs_vfsop_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
77984d9c625SLionel Sambuc {
78084d9c625SLionel Sambuc 
78184d9c625SLionel Sambuc 	return EOPNOTSUPP;
78284d9c625SLionel Sambuc }
78384d9c625SLionel Sambuc 
78484d9c625SLionel Sambuc int
puffs_vfsop_extattrctl(struct mount * mp,int cmd,struct vnode * vp,int attrnamespace,const char * attrname)78584d9c625SLionel Sambuc puffs_vfsop_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
78684d9c625SLionel Sambuc 	int attrnamespace, const char *attrname)
78784d9c625SLionel Sambuc {
78884d9c625SLionel Sambuc 	PUFFS_MSG_VARS(vfs, extattrctl);
78984d9c625SLionel Sambuc 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
79084d9c625SLionel Sambuc 	struct puffs_node *pnp;
79184d9c625SLionel Sambuc 	puffs_cookie_t pnc;
79284d9c625SLionel Sambuc 	int error, flags;
79384d9c625SLionel Sambuc 
79484d9c625SLionel Sambuc 	if (vp) {
79584d9c625SLionel Sambuc 		/* doesn't make sense for puffs servers */
79684d9c625SLionel Sambuc 		if (vp->v_mount != mp)
79784d9c625SLionel Sambuc 			return EXDEV;
79884d9c625SLionel Sambuc 		pnp = vp->v_data;
79984d9c625SLionel Sambuc 		pnc = pnp->pn_cookie;
80084d9c625SLionel Sambuc 		flags = PUFFS_EXTATTRCTL_HASNODE;
80184d9c625SLionel Sambuc 	} else {
80284d9c625SLionel Sambuc 		pnp = pnc = NULL;
80384d9c625SLionel Sambuc 		flags = 0;
80484d9c625SLionel Sambuc 	}
80584d9c625SLionel Sambuc 
80684d9c625SLionel Sambuc 	PUFFS_MSG_ALLOC(vfs, extattrctl);
80784d9c625SLionel Sambuc 	extattrctl_msg->pvfsr_cmd = cmd;
80884d9c625SLionel Sambuc 	extattrctl_msg->pvfsr_attrnamespace = attrnamespace;
80984d9c625SLionel Sambuc 	extattrctl_msg->pvfsr_flags = flags;
81084d9c625SLionel Sambuc 	if (attrname) {
81184d9c625SLionel Sambuc 		strlcpy(extattrctl_msg->pvfsr_attrname, attrname,
81284d9c625SLionel Sambuc 		    sizeof(extattrctl_msg->pvfsr_attrname));
81384d9c625SLionel Sambuc 		extattrctl_msg->pvfsr_flags |= PUFFS_EXTATTRCTL_HASATTRNAME;
81484d9c625SLionel Sambuc 	}
81584d9c625SLionel Sambuc 	puffs_msg_setinfo(park_extattrctl,
81684d9c625SLionel Sambuc 	    PUFFSOP_VFS, PUFFS_VFS_EXTATTRCTL, pnc);
81784d9c625SLionel Sambuc 
81884d9c625SLionel Sambuc 	puffs_msg_enqueue(pmp, park_extattrctl);
81984d9c625SLionel Sambuc 	if (vp) {
82084d9c625SLionel Sambuc 		mutex_enter(&pnp->pn_mtx);
82184d9c625SLionel Sambuc 		puffs_referencenode(pnp);
82284d9c625SLionel Sambuc 		mutex_exit(&pnp->pn_mtx);
82384d9c625SLionel Sambuc 		VOP_UNLOCK(vp);
82484d9c625SLionel Sambuc 	}
82584d9c625SLionel Sambuc 	error = puffs_msg_wait2(pmp, park_extattrctl, pnp, NULL);
82684d9c625SLionel Sambuc 	PUFFS_MSG_RELEASE(extattrctl);
82784d9c625SLionel Sambuc 	if (vp) {
82884d9c625SLionel Sambuc 		puffs_releasenode(pnp);
82984d9c625SLionel Sambuc 	}
83084d9c625SLionel Sambuc 
83184d9c625SLionel Sambuc 	return checkerr(pmp, error, __func__);
83284d9c625SLionel Sambuc }
83384d9c625SLionel Sambuc 
83484d9c625SLionel Sambuc const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
83584d9c625SLionel Sambuc 	&puffs_vnodeop_opv_desc,
83684d9c625SLionel Sambuc 	&puffs_specop_opv_desc,
83784d9c625SLionel Sambuc 	&puffs_fifoop_opv_desc,
83884d9c625SLionel Sambuc 	&puffs_msgop_opv_desc,
83984d9c625SLionel Sambuc 	NULL,
84084d9c625SLionel Sambuc };
84184d9c625SLionel Sambuc 
84284d9c625SLionel Sambuc struct vfsops puffs_vfsops = {
843*0a6a1f1dSLionel Sambuc 	.vfs_name = MOUNT_PUFFS,
844*0a6a1f1dSLionel Sambuc 	.vfs_min_mount_data = sizeof (struct puffs_kargs),
845*0a6a1f1dSLionel Sambuc 	.vfs_mount = puffs_vfsop_mount,
846*0a6a1f1dSLionel Sambuc 	.vfs_start = puffs_vfsop_start,
847*0a6a1f1dSLionel Sambuc 	.vfs_unmount = puffs_vfsop_unmount,
848*0a6a1f1dSLionel Sambuc 	.vfs_root = puffs_vfsop_root,
849*0a6a1f1dSLionel Sambuc 	.vfs_quotactl = (void *)eopnotsupp,
850*0a6a1f1dSLionel Sambuc 	.vfs_statvfs = puffs_vfsop_statvfs,
851*0a6a1f1dSLionel Sambuc 	.vfs_sync = puffs_vfsop_sync,
852*0a6a1f1dSLionel Sambuc 	.vfs_vget = (void *)eopnotsupp,
853*0a6a1f1dSLionel Sambuc 	.vfs_loadvnode = puffs_vfsop_loadvnode,
854*0a6a1f1dSLionel Sambuc 	.vfs_fhtovp = puffs_vfsop_fhtovp,
855*0a6a1f1dSLionel Sambuc 	.vfs_vptofh = puffs_vfsop_vptofh,
856*0a6a1f1dSLionel Sambuc 	.vfs_init = puffs_vfsop_init,
857*0a6a1f1dSLionel Sambuc 	.vfs_done = puffs_vfsop_done,
858*0a6a1f1dSLionel Sambuc 	.vfs_snapshot = puffs_vfsop_snapshot,
859*0a6a1f1dSLionel Sambuc 	.vfs_extattrctl = puffs_vfsop_extattrctl,
860*0a6a1f1dSLionel Sambuc 	.vfs_suspendctl = (void *)eopnotsupp,
861*0a6a1f1dSLionel Sambuc 	.vfs_renamelock_enter = genfs_renamelock_enter,
862*0a6a1f1dSLionel Sambuc 	.vfs_renamelock_exit = genfs_renamelock_exit,
863*0a6a1f1dSLionel Sambuc 	.vfs_fsync = (void *)eopnotsupp,
864*0a6a1f1dSLionel Sambuc 	.vfs_opv_descs = puffs_vnodeopv_descs
86584d9c625SLionel Sambuc };
86684d9c625SLionel Sambuc 
86784d9c625SLionel Sambuc static int
puffs_modcmd(modcmd_t cmd,void * arg)86884d9c625SLionel Sambuc puffs_modcmd(modcmd_t cmd, void *arg)
86984d9c625SLionel Sambuc {
87084d9c625SLionel Sambuc 
87184d9c625SLionel Sambuc 	switch (cmd) {
87284d9c625SLionel Sambuc 	case MODULE_CMD_INIT:
87384d9c625SLionel Sambuc 		return vfs_attach(&puffs_vfsops);
87484d9c625SLionel Sambuc 	case MODULE_CMD_FINI:
87584d9c625SLionel Sambuc 		return vfs_detach(&puffs_vfsops);
87684d9c625SLionel Sambuc 	default:
87784d9c625SLionel Sambuc 		return ENOTTY;
87884d9c625SLionel Sambuc 	}
87984d9c625SLionel Sambuc }
880