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