xref: /dflybsd-src/sys/vfs/fuse/fuse_vfsops.c (revision 1a8e5e4cf0cfbe16676810f7edca73f98bb9b8f5)
15812c3ccSTomohiro Kusumi /*-
25812c3ccSTomohiro Kusumi  * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
35812c3ccSTomohiro Kusumi  * Copyright (c) 2019 The DragonFly Project
45812c3ccSTomohiro Kusumi  * All rights reserved.
55812c3ccSTomohiro Kusumi  *
65812c3ccSTomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
75812c3ccSTomohiro Kusumi  * modification, are permitted provided that the following conditions
85812c3ccSTomohiro Kusumi  * are met:
95812c3ccSTomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
105812c3ccSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
115812c3ccSTomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
125812c3ccSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in the
135812c3ccSTomohiro Kusumi  *    documentation and/or other materials provided with the distribution.
145812c3ccSTomohiro Kusumi  *
155812c3ccSTomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165812c3ccSTomohiro Kusumi  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175812c3ccSTomohiro Kusumi  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185812c3ccSTomohiro Kusumi  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195812c3ccSTomohiro Kusumi  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205812c3ccSTomohiro Kusumi  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215812c3ccSTomohiro Kusumi  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225812c3ccSTomohiro Kusumi  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235812c3ccSTomohiro Kusumi  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245812c3ccSTomohiro Kusumi  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255812c3ccSTomohiro Kusumi  * SUCH DAMAGE.
265812c3ccSTomohiro Kusumi  */
275812c3ccSTomohiro Kusumi 
285812c3ccSTomohiro Kusumi #include "fuse.h"
295812c3ccSTomohiro Kusumi 
305812c3ccSTomohiro Kusumi #include <sys/device.h>
315812c3ccSTomohiro Kusumi #include <sys/devfs.h>
325812c3ccSTomohiro Kusumi #include <sys/nlookup.h>
335812c3ccSTomohiro Kusumi #include <sys/file.h>
345812c3ccSTomohiro Kusumi #include <sys/sysctl.h>
355812c3ccSTomohiro Kusumi #include <sys/statvfs.h>
362b3f93eaSMatthew Dillon #include <sys/caps.h>
375d0d0bafSMatthew Dillon #include <sys/spinlock.h>
385d0d0bafSMatthew Dillon 
395d0d0bafSMatthew Dillon #include <sys/spinlock2.h>
405812c3ccSTomohiro Kusumi 
415812c3ccSTomohiro Kusumi int fuse_debug = 0;
425812c3ccSTomohiro Kusumi 
435812c3ccSTomohiro Kusumi SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RD, 0, "FUSE");
445812c3ccSTomohiro Kusumi 
455812c3ccSTomohiro Kusumi SYSCTL_INT(_vfs_fuse, OID_AUTO, version_major, CTLFLAG_RD, NULL,
465812c3ccSTomohiro Kusumi     FUSE_KERNEL_VERSION, "FUSE kernel version (major)");
475812c3ccSTomohiro Kusumi SYSCTL_INT(_vfs_fuse, OID_AUTO, version_minor, CTLFLAG_RD, NULL,
485812c3ccSTomohiro Kusumi     FUSE_KERNEL_MINOR_VERSION, "FUSE kernel version (minor)");
495812c3ccSTomohiro Kusumi 
505812c3ccSTomohiro Kusumi SYSCTL_INT(_vfs_fuse, OID_AUTO, debug, CTLFLAG_RW, &fuse_debug, 1, "");
515812c3ccSTomohiro Kusumi 
525812c3ccSTomohiro Kusumi int
fuse_cmp_version(struct fuse_mount * fmp,uint32_t major,uint32_t minor)535812c3ccSTomohiro Kusumi fuse_cmp_version(struct fuse_mount *fmp, uint32_t major, uint32_t minor)
545812c3ccSTomohiro Kusumi {
555812c3ccSTomohiro Kusumi 	if (fmp->abi_major == major && fmp->abi_minor == minor)
565812c3ccSTomohiro Kusumi 		return 0;
575812c3ccSTomohiro Kusumi 
585812c3ccSTomohiro Kusumi 	if (fmp->abi_major > major ||
595812c3ccSTomohiro Kusumi 	    (fmp->abi_major == major && fmp->abi_minor > minor))
605812c3ccSTomohiro Kusumi 		return 1;
615812c3ccSTomohiro Kusumi 
625812c3ccSTomohiro Kusumi 	return -1;
635812c3ccSTomohiro Kusumi }
645812c3ccSTomohiro Kusumi 
655812c3ccSTomohiro Kusumi int
fuse_mount_kill(struct fuse_mount * fmp)665812c3ccSTomohiro Kusumi fuse_mount_kill(struct fuse_mount *fmp)
675812c3ccSTomohiro Kusumi {
685812c3ccSTomohiro Kusumi 	if (!fuse_test_dead(fmp)) {
695812c3ccSTomohiro Kusumi 		fuse_set_dead(fmp);
705812c3ccSTomohiro Kusumi 		wakeup(fmp);
715812c3ccSTomohiro Kusumi 		KNOTE(&fmp->kq.ki_note, 0);
725812c3ccSTomohiro Kusumi 		return 0;
735812c3ccSTomohiro Kusumi 	}
745812c3ccSTomohiro Kusumi 
755812c3ccSTomohiro Kusumi 	return -1;
765812c3ccSTomohiro Kusumi }
775812c3ccSTomohiro Kusumi 
785812c3ccSTomohiro Kusumi int
fuse_mount_free(struct fuse_mount * fmp)795812c3ccSTomohiro Kusumi fuse_mount_free(struct fuse_mount *fmp)
805812c3ccSTomohiro Kusumi {
815812c3ccSTomohiro Kusumi 	if (refcount_release(&fmp->refcnt)) {
825812c3ccSTomohiro Kusumi 		fuse_dbg("fmp=%p free\n", fmp);
835812c3ccSTomohiro Kusumi 		mtx_uninit(&fmp->ipc_lock);
845812c3ccSTomohiro Kusumi 		mtx_uninit(&fmp->mnt_lock);
85*1a8e5e4cSMatthew Dillon 		mtx_uninit(&fmp->ino_lock);
865812c3ccSTomohiro Kusumi 		crfree(fmp->cred);
875812c3ccSTomohiro Kusumi 		kfree(fmp, M_TEMP);
885812c3ccSTomohiro Kusumi 		return 0;
895812c3ccSTomohiro Kusumi 	}
905812c3ccSTomohiro Kusumi 	fuse_dbg("fmp=%p %u refcnt left\n", fmp, fmp->refcnt);
915812c3ccSTomohiro Kusumi 
925812c3ccSTomohiro Kusumi 	return -1;
935812c3ccSTomohiro Kusumi }
945812c3ccSTomohiro Kusumi 
955812c3ccSTomohiro Kusumi static int
fuse_mount(struct mount * mp,char * mntpt,caddr_t data,struct ucred * cred)965812c3ccSTomohiro Kusumi fuse_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred)
975812c3ccSTomohiro Kusumi {
985812c3ccSTomohiro Kusumi 	struct statfs *sbp = &mp->mnt_stat;
995812c3ccSTomohiro Kusumi 	struct vnode *devvp;
1005812c3ccSTomohiro Kusumi 	struct file *file;
1015812c3ccSTomohiro Kusumi 	struct nlookupdata nd;
1025812c3ccSTomohiro Kusumi 	struct fuse_mount_info args;
1035812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp;
1045812c3ccSTomohiro Kusumi 	struct fuse_ipc *fip;
1055812c3ccSTomohiro Kusumi 	struct fuse_init_in *fii;
1065812c3ccSTomohiro Kusumi 	struct fuse_init_out *fio;
1075812c3ccSTomohiro Kusumi 	char subtype[512];
1085812c3ccSTomohiro Kusumi 	int error;
1095812c3ccSTomohiro Kusumi 
1105812c3ccSTomohiro Kusumi 	if (mp->mnt_flag & MNT_UPDATE)
1115812c3ccSTomohiro Kusumi 		return EOPNOTSUPP;
1125812c3ccSTomohiro Kusumi 
1135812c3ccSTomohiro Kusumi 	error = copyin(data, &args, sizeof(args));
1145812c3ccSTomohiro Kusumi 	if (error)
1155812c3ccSTomohiro Kusumi 		return error;
1165812c3ccSTomohiro Kusumi 
1175812c3ccSTomohiro Kusumi 	memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname));
1185812c3ccSTomohiro Kusumi 	error = copyinstr(args.from, sbp->f_mntfromname,
1195812c3ccSTomohiro Kusumi 	    sizeof(sbp->f_mntfromname), NULL);
1205812c3ccSTomohiro Kusumi 	if (error)
1215812c3ccSTomohiro Kusumi 		return error;
1225812c3ccSTomohiro Kusumi 
1235812c3ccSTomohiro Kusumi 	memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname));
1245812c3ccSTomohiro Kusumi 	error = copyinstr(mntpt, sbp->f_mntonname, sizeof(sbp->f_mntonname),
1255812c3ccSTomohiro Kusumi 	    NULL);
1265812c3ccSTomohiro Kusumi 	if (error)
1275812c3ccSTomohiro Kusumi 		return error;
1285812c3ccSTomohiro Kusumi 
1295812c3ccSTomohiro Kusumi 	memset(subtype, 0, sizeof(subtype));
130df8dfe6eSKyle Butt 	if (args.subtype != NULL) {
1315812c3ccSTomohiro Kusumi 		error = copyinstr(args.subtype, subtype, sizeof(subtype), NULL);
1325812c3ccSTomohiro Kusumi 		if (error)
1335812c3ccSTomohiro Kusumi 			return error;
1345812c3ccSTomohiro Kusumi 		if (strlen(subtype)) {
1355812c3ccSTomohiro Kusumi 			strlcat(sbp->f_fstypename, ".", sizeof(sbp->f_fstypename));
1365812c3ccSTomohiro Kusumi 			strlcat(sbp->f_fstypename, subtype, sizeof(sbp->f_fstypename));
1375812c3ccSTomohiro Kusumi 		}
138df8dfe6eSKyle Butt 	}
1395812c3ccSTomohiro Kusumi 
1405812c3ccSTomohiro Kusumi 	error = nlookup_init(&nd, sbp->f_mntfromname, UIO_SYSSPACE, NLC_FOLLOW);
1415812c3ccSTomohiro Kusumi 	if (!error) {
1425812c3ccSTomohiro Kusumi 		error = nlookup(&nd);
1435812c3ccSTomohiro Kusumi 		if (!error)
1445812c3ccSTomohiro Kusumi 			error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
1455812c3ccSTomohiro Kusumi 		nlookup_done(&nd);
1465812c3ccSTomohiro Kusumi 	}
1475812c3ccSTomohiro Kusumi 	if (error)
1485812c3ccSTomohiro Kusumi 		return error;
1495812c3ccSTomohiro Kusumi 	if (!devvp)
1505812c3ccSTomohiro Kusumi 		return ENODEV;
1515812c3ccSTomohiro Kusumi 
1525812c3ccSTomohiro Kusumi 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1535812c3ccSTomohiro Kusumi 	error = VOP_ACCESS(devvp, VREAD | VWRITE, cred);
1542b3f93eaSMatthew Dillon 	if (error == 0)
1552b3f93eaSMatthew Dillon 		error = caps_priv_check(cred, SYSCAP_NOMOUNT_FUSE);
1565812c3ccSTomohiro Kusumi 	if (error) {
1575812c3ccSTomohiro Kusumi 		vput(devvp);
1585812c3ccSTomohiro Kusumi 		return error;
1595812c3ccSTomohiro Kusumi 	}
1605812c3ccSTomohiro Kusumi 	vn_unlock(devvp);
1615812c3ccSTomohiro Kusumi 
1625812c3ccSTomohiro Kusumi 	fuse_dbg("fd=%d\n", args.fd);
1635812c3ccSTomohiro Kusumi 	file = holdfp_fdp(curthread->td_proc->p_fd, args.fd, FREAD | FWRITE);
1645812c3ccSTomohiro Kusumi 	if (!file) {
1655812c3ccSTomohiro Kusumi 		vrele(devvp);
1665812c3ccSTomohiro Kusumi 		return EBADF;
1675812c3ccSTomohiro Kusumi 	}
1685812c3ccSTomohiro Kusumi 	error = devfs_get_cdevpriv(file, (void**)&fmp);
1695812c3ccSTomohiro Kusumi 	dropfp(curthread, args.fd, file);
1705812c3ccSTomohiro Kusumi 	if (error) {
1715812c3ccSTomohiro Kusumi 		vrele(devvp);
1725812c3ccSTomohiro Kusumi 		return error;
1735812c3ccSTomohiro Kusumi 	}
1745812c3ccSTomohiro Kusumi 	KKASSERT(fmp);
1755812c3ccSTomohiro Kusumi 
1765812c3ccSTomohiro Kusumi 	fmp->mp = mp;
1775812c3ccSTomohiro Kusumi 	fmp->dead = false;
1785812c3ccSTomohiro Kusumi 	mtx_init(&fmp->mnt_lock, "fuse_mnt_lock");
1795812c3ccSTomohiro Kusumi 	mtx_init(&fmp->ipc_lock, "fuse_ipc_lock");
180*1a8e5e4cSMatthew Dillon 	mtx_init(&fmp->ino_lock, "fuse_ino_lock");
1815812c3ccSTomohiro Kusumi 	TAILQ_INIT(&fmp->request_head);
1825812c3ccSTomohiro Kusumi 	TAILQ_INIT(&fmp->reply_head);
183*1a8e5e4cSMatthew Dillon 	RB_INIT(&fmp->node_head);
1845812c3ccSTomohiro Kusumi 	fmp->devvp = devvp;
1855812c3ccSTomohiro Kusumi 	fmp->cred = crhold(cred);
1865812c3ccSTomohiro Kusumi 	KKASSERT(fmp->refcnt > 0);
1875812c3ccSTomohiro Kusumi 	refcount_acquire(&fmp->refcnt);
1885812c3ccSTomohiro Kusumi 
1895812c3ccSTomohiro Kusumi 	mp->mnt_flag |= MNT_LOCAL;
1905812c3ccSTomohiro Kusumi 	mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
1915d0d0bafSMatthew Dillon 	mp->mnt_kern_flag |= MNTK_THR_SYNC;
1925812c3ccSTomohiro Kusumi 	mp->mnt_data = (qaddr_t)fmp;
1935812c3ccSTomohiro Kusumi 
1945812c3ccSTomohiro Kusumi 	fuse_node_new(fmp, FUSE_ROOT_ID, VDIR, &fmp->rfnp);
1955812c3ccSTomohiro Kusumi 	KKASSERT(fmp->rfnp->ino == FUSE_ROOT_ID);
1965812c3ccSTomohiro Kusumi 
1975812c3ccSTomohiro Kusumi 	vfs_getnewfsid(mp);
1985812c3ccSTomohiro Kusumi 	vfs_add_vnodeops(mp, &fuse_vnode_vops, &mp->mnt_vn_norm_ops);
1995812c3ccSTomohiro Kusumi 	vfs_add_vnodeops(mp, &fuse_spec_vops, &mp->mnt_vn_spec_ops);
2005d0d0bafSMatthew Dillon 	/* XXX fifo ops */
2015812c3ccSTomohiro Kusumi 
2025812c3ccSTomohiro Kusumi 	fip = fuse_ipc_get(fmp, sizeof(*fii));
2035812c3ccSTomohiro Kusumi 	fii = fuse_ipc_fill(fip, FUSE_INIT, FUSE_ROOT_ID, NULL);
2045812c3ccSTomohiro Kusumi 	fii->major = FUSE_KERNEL_VERSION;
2055812c3ccSTomohiro Kusumi 	fii->minor = FUSE_KERNEL_MINOR_VERSION;
2065812c3ccSTomohiro Kusumi 	fii->max_readahead = FUSE_BLKSIZE;
2075812c3ccSTomohiro Kusumi 	/* unused */
2085812c3ccSTomohiro Kusumi 	//fii->flags = ...;
2095812c3ccSTomohiro Kusumi 
2105812c3ccSTomohiro Kusumi 	error = fuse_ipc_tx(fip);
2115812c3ccSTomohiro Kusumi 	if (error) {
2125812c3ccSTomohiro Kusumi 		vrele(devvp);
2135812c3ccSTomohiro Kusumi 		return error;
2145812c3ccSTomohiro Kusumi 	}
2155812c3ccSTomohiro Kusumi 
2165812c3ccSTomohiro Kusumi 	fio = fuse_out_data(fip);
2175812c3ccSTomohiro Kusumi 	fmp->abi_major = fio->major;
2185812c3ccSTomohiro Kusumi 	fmp->abi_minor = fio->minor;
2195812c3ccSTomohiro Kusumi 	fmp->max_write = fio->max_write;
2205812c3ccSTomohiro Kusumi 
2215812c3ccSTomohiro Kusumi 	if (fuse_cmp_version(fmp, 7, 0) < 0) {
2225812c3ccSTomohiro Kusumi 		fuse_ipc_put(fip);
2235812c3ccSTomohiro Kusumi 		vrele(devvp);
2245812c3ccSTomohiro Kusumi 		return EPROTONOSUPPORT;
2255812c3ccSTomohiro Kusumi 	}
2265812c3ccSTomohiro Kusumi 
2275812c3ccSTomohiro Kusumi 	/* unused */
2285812c3ccSTomohiro Kusumi 	//fio->max_readahead
2295812c3ccSTomohiro Kusumi 	//fio->flags
2305812c3ccSTomohiro Kusumi 	//fio->max_background
2315812c3ccSTomohiro Kusumi 	//fio->congestion_threshold
2325812c3ccSTomohiro Kusumi 	//fio->time_gran
2335812c3ccSTomohiro Kusumi 	//fio->max_pages
2345812c3ccSTomohiro Kusumi 	fuse_print("FUSE UABI %d.%d\n", fmp->abi_major, fmp->abi_minor);
2355812c3ccSTomohiro Kusumi 
2365812c3ccSTomohiro Kusumi 	fuse_ipc_put(fip);
2375812c3ccSTomohiro Kusumi 
2385812c3ccSTomohiro Kusumi 	VFS_STATFS(mp, &mp->mnt_stat, cred);
2395812c3ccSTomohiro Kusumi 
2405d0d0bafSMatthew Dillon 	spin_init(&fmp->helper_spin, "fuse_spin");
2415d0d0bafSMatthew Dillon 	TAILQ_INIT(&fmp->bioq);
2425d0d0bafSMatthew Dillon 	lwkt_create(fuse_io_thread, fmp, &fmp->helper_td,
2435d0d0bafSMatthew Dillon 		    NULL, 0, -1, "fuse_helper");
2445d0d0bafSMatthew Dillon 
2455812c3ccSTomohiro Kusumi 	return 0;
2465812c3ccSTomohiro Kusumi }
2475812c3ccSTomohiro Kusumi 
2485812c3ccSTomohiro Kusumi static int
fuse_unmount(struct mount * mp,int mntflags)2495812c3ccSTomohiro Kusumi fuse_unmount(struct mount *mp, int mntflags)
2505812c3ccSTomohiro Kusumi {
2515812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp = VFSTOFUSE(mp);
2525812c3ccSTomohiro Kusumi 	struct fuse_ipc *fip;
2535812c3ccSTomohiro Kusumi 	int error, flags = 0;
2545812c3ccSTomohiro Kusumi 
2555812c3ccSTomohiro Kusumi 	mtx_lock(&fmp->mnt_lock);
2565812c3ccSTomohiro Kusumi 	if (mntflags & MNT_FORCE)
2575812c3ccSTomohiro Kusumi 		flags |= FORCECLOSE;
2585812c3ccSTomohiro Kusumi 
2595812c3ccSTomohiro Kusumi 	error = vflush(mp, 0, flags);
2605812c3ccSTomohiro Kusumi 	if (error) {
2615812c3ccSTomohiro Kusumi 		mtx_unlock(&fmp->mnt_lock);
2625812c3ccSTomohiro Kusumi 		fuse_dbg("vflush error=%d\n", error);
2635812c3ccSTomohiro Kusumi 		return error;
2645812c3ccSTomohiro Kusumi 	}
2655812c3ccSTomohiro Kusumi 
2665812c3ccSTomohiro Kusumi 	if (!fuse_test_dead(fmp)) {
2675812c3ccSTomohiro Kusumi 		fuse_dbg("not dead yet, destroying\n");
2685812c3ccSTomohiro Kusumi 		fip = fuse_ipc_get(fmp, 0);
2695812c3ccSTomohiro Kusumi 		fuse_ipc_fill(fip, FUSE_DESTROY, FUSE_ROOT_ID, NULL);
2705812c3ccSTomohiro Kusumi 		if (!fuse_ipc_tx(fip))
2715812c3ccSTomohiro Kusumi 			fuse_ipc_put(fip);
2725812c3ccSTomohiro Kusumi 		fuse_mount_kill(fmp);
2735812c3ccSTomohiro Kusumi 	}
2745812c3ccSTomohiro Kusumi 
2755d0d0bafSMatthew Dillon 	/* Wait for helper thread to exit */
2765d0d0bafSMatthew Dillon 	while (fmp->helper_td) {
2775d0d0bafSMatthew Dillon 		wakeup(&fmp->helper_td);
2785d0d0bafSMatthew Dillon 		tsleep(&fmp->helper_td, 0, "fusehumnt", 2);
2795d0d0bafSMatthew Dillon 	}
2805d0d0bafSMatthew Dillon 
2815d0d0bafSMatthew Dillon 	KKASSERT(fmp->rfnp->vp == NULL);
282*1a8e5e4cSMatthew Dillon 	fuse_node_free(fmp, fmp->rfnp);
2835d0d0bafSMatthew Dillon 	fmp->rfnp = NULL;
2845d0d0bafSMatthew Dillon 
2855812c3ccSTomohiro Kusumi 	/* The userspace fs will exit anyway after FUSE_DESTROY. */
2865812c3ccSTomohiro Kusumi 	vn_lock(fmp->devvp, LK_EXCLUSIVE | LK_RETRY);
2875812c3ccSTomohiro Kusumi 	VOP_CLOSE(fmp->devvp, FREAD | FWRITE, NULL);
2885812c3ccSTomohiro Kusumi 	vn_unlock(fmp->devvp);
2895812c3ccSTomohiro Kusumi 
2905812c3ccSTomohiro Kusumi 	vrele(fmp->devvp);
2915812c3ccSTomohiro Kusumi 	mtx_unlock(&fmp->mnt_lock);
2925812c3ccSTomohiro Kusumi 
2935812c3ccSTomohiro Kusumi 	fuse_mount_free(fmp);
2945812c3ccSTomohiro Kusumi 	mp->mnt_data = NULL;
2955812c3ccSTomohiro Kusumi 	mp->mnt_flag &= ~MNT_LOCAL;
2965812c3ccSTomohiro Kusumi 
2975812c3ccSTomohiro Kusumi 	fuse_dbg("unmount done\n");
2985812c3ccSTomohiro Kusumi 
2995812c3ccSTomohiro Kusumi 	return 0;
3005812c3ccSTomohiro Kusumi }
3015812c3ccSTomohiro Kusumi 
3025d0d0bafSMatthew Dillon /*
3035d0d0bafSMatthew Dillon  *
3045d0d0bafSMatthew Dillon  * fuse_sync() and friends
3055d0d0bafSMatthew Dillon  *
3065d0d0bafSMatthew Dillon  * This is an alternative faster way for DragonFlyBSD to flush vnodes,
3075d0d0bafSMatthew Dillon  * but requires a bit of code structure.  vsetisdirty() puts the vnode
3085d0d0bafSMatthew Dillon  * on a per-thread syncer list.  When the list is non-empty, .vfs_sync()
3095d0d0bafSMatthew Dillon  * is called periodically to flush dirty vnodes.
3105d0d0bafSMatthew Dillon  *
3115d0d0bafSMatthew Dillon  * In the case of fuse, at the moment file writes are asynchronous and
3125d0d0bafSMatthew Dillon  * other attribute changes are synchronous so we only have to check for
3135d0d0bafSMatthew Dillon  * dirty buffers.
3145d0d0bafSMatthew Dillon  */
3155d0d0bafSMatthew Dillon static int fuse_sync_scan1(struct mount *mp, struct vnode *vp, void *data);
3165d0d0bafSMatthew Dillon static int fuse_sync_scan2(struct mount *mp, struct vnode *vp, void *data);
3175d0d0bafSMatthew Dillon 
3185d0d0bafSMatthew Dillon struct scaninfo {
3195d0d0bafSMatthew Dillon 	int rescan;
3205d0d0bafSMatthew Dillon 	int waitfor;
3215d0d0bafSMatthew Dillon 	int allerror;
3225d0d0bafSMatthew Dillon };
3235d0d0bafSMatthew Dillon 
3245d0d0bafSMatthew Dillon 
3255d0d0bafSMatthew Dillon static int
fuse_sync(struct mount * mp,int waitfor)3265d0d0bafSMatthew Dillon fuse_sync(struct mount *mp, int waitfor)
3275d0d0bafSMatthew Dillon {
3285d0d0bafSMatthew Dillon 	struct scaninfo scaninfo;
3295d0d0bafSMatthew Dillon 
3305d0d0bafSMatthew Dillon 	scaninfo.allerror = 0;
3315d0d0bafSMatthew Dillon 	scaninfo.rescan = 1;
3325d0d0bafSMatthew Dillon 	scaninfo.waitfor = waitfor;
3335d0d0bafSMatthew Dillon 	while (scaninfo.rescan) {
3345d0d0bafSMatthew Dillon 		scaninfo.rescan = 0;
3355d0d0bafSMatthew Dillon 		vmntvnodescan(mp, VMSC_GETVP|VMSC_NOWAIT,
3365d0d0bafSMatthew Dillon 			      fuse_sync_scan1, fuse_sync_scan2, &scaninfo);
3375d0d0bafSMatthew Dillon 	}
3385d0d0bafSMatthew Dillon 	return (scaninfo.allerror);
3395d0d0bafSMatthew Dillon }
3405d0d0bafSMatthew Dillon 
3415d0d0bafSMatthew Dillon /*
3425d0d0bafSMatthew Dillon  * Fast pre-check requires flush?
3435d0d0bafSMatthew Dillon  */
3445d0d0bafSMatthew Dillon static int
fuse_sync_scan1(struct mount * mp,struct vnode * vp,void * data)3455d0d0bafSMatthew Dillon fuse_sync_scan1(struct mount *mp, struct vnode *vp, void *data)
3465d0d0bafSMatthew Dillon {
3475d0d0bafSMatthew Dillon 	if (RB_EMPTY(&vp->v_rbdirty_tree))
3485d0d0bafSMatthew Dillon 		return -1;
3495d0d0bafSMatthew Dillon 	return 0;
3505d0d0bafSMatthew Dillon }
3515d0d0bafSMatthew Dillon 
3525d0d0bafSMatthew Dillon /*
3535d0d0bafSMatthew Dillon  * Main flush (re-check)
3545d0d0bafSMatthew Dillon  */
3555d0d0bafSMatthew Dillon static int
fuse_sync_scan2(struct mount * mp,struct vnode * vp,void * data)3565d0d0bafSMatthew Dillon fuse_sync_scan2(struct mount *mp, struct vnode *vp, void *data)
3575d0d0bafSMatthew Dillon {
3585d0d0bafSMatthew Dillon 	struct scaninfo *info = data;
3595d0d0bafSMatthew Dillon 	int error;
3605d0d0bafSMatthew Dillon 
3615d0d0bafSMatthew Dillon 	if ((error = VOP_FSYNC(vp, info->waitfor, 0)) != 0)
3625d0d0bafSMatthew Dillon 		info->allerror = error;
3635d0d0bafSMatthew Dillon 	return 0;
3645d0d0bafSMatthew Dillon }
3655d0d0bafSMatthew Dillon 
3665812c3ccSTomohiro Kusumi static int
fuse_root(struct mount * mp,struct vnode ** vpp)3675812c3ccSTomohiro Kusumi fuse_root(struct mount *mp, struct vnode **vpp)
3685812c3ccSTomohiro Kusumi {
3695812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp = VFSTOFUSE(mp);
3705812c3ccSTomohiro Kusumi 	int error;
3715812c3ccSTomohiro Kusumi 
3725812c3ccSTomohiro Kusumi 	KASSERT(fmp->rfnp, ("no root node"));
3735812c3ccSTomohiro Kusumi 	KKASSERT(fmp->rfnp->fmp);
3745812c3ccSTomohiro Kusumi 
3755d0d0bafSMatthew Dillon 	error = fuse_node_vn(fmp->rfnp, vpp);
3765812c3ccSTomohiro Kusumi 	if (!error) {
3775812c3ccSTomohiro Kusumi 		struct vnode *vp = *vpp;
3785d0d0bafSMatthew Dillon 		vsetflags(vp, VROOT);
3795812c3ccSTomohiro Kusumi 		KKASSERT(vp->v_type == VDIR);
3805812c3ccSTomohiro Kusumi 	}
3815812c3ccSTomohiro Kusumi 
3825812c3ccSTomohiro Kusumi 	return error;
3835812c3ccSTomohiro Kusumi }
3845812c3ccSTomohiro Kusumi 
3855812c3ccSTomohiro Kusumi static int
fuse_statfs(struct mount * mp,struct statfs * sbp,struct ucred * cred)3865812c3ccSTomohiro Kusumi fuse_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
3875812c3ccSTomohiro Kusumi {
3885812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp = VFSTOFUSE(mp);
3895812c3ccSTomohiro Kusumi 	struct fuse_ipc *fip;
3905812c3ccSTomohiro Kusumi 	struct fuse_statfs_out *fso;
3915812c3ccSTomohiro Kusumi 	int error;
3925812c3ccSTomohiro Kusumi 
3935812c3ccSTomohiro Kusumi 	fip = fuse_ipc_get(fmp, 0);
3945812c3ccSTomohiro Kusumi 	fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred);
3955812c3ccSTomohiro Kusumi 	error = fuse_ipc_tx(fip);
3965812c3ccSTomohiro Kusumi 	if (error)
3975812c3ccSTomohiro Kusumi 		return error;
3985812c3ccSTomohiro Kusumi 
3995812c3ccSTomohiro Kusumi 	fso = fuse_out_data(fip);
4005812c3ccSTomohiro Kusumi 
4015812c3ccSTomohiro Kusumi 	mtx_lock(&fmp->mnt_lock);
4025812c3ccSTomohiro Kusumi 	sbp->f_bsize = fso->st.frsize;
4035812c3ccSTomohiro Kusumi 	sbp->f_iosize = FUSE_BLKSIZE;
4045812c3ccSTomohiro Kusumi 	sbp->f_blocks = fso->st.blocks;
4055812c3ccSTomohiro Kusumi 	sbp->f_bfree = fso->st.bfree;
4065812c3ccSTomohiro Kusumi 	sbp->f_bavail = fso->st.bavail;
4075812c3ccSTomohiro Kusumi 	sbp->f_files = fso->st.files;
4085812c3ccSTomohiro Kusumi 	sbp->f_ffree = fso->st.ffree;
4095812c3ccSTomohiro Kusumi 	mtx_unlock(&fmp->mnt_lock);
4105812c3ccSTomohiro Kusumi 
4115812c3ccSTomohiro Kusumi 	fuse_ipc_put(fip);
4125812c3ccSTomohiro Kusumi 
4135812c3ccSTomohiro Kusumi 	return 0;
4145812c3ccSTomohiro Kusumi }
4155812c3ccSTomohiro Kusumi 
4165812c3ccSTomohiro Kusumi static int
fuse_statvfs(struct mount * mp,struct statvfs * sbp,struct ucred * cred)4175812c3ccSTomohiro Kusumi fuse_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
4185812c3ccSTomohiro Kusumi {
4195812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp = VFSTOFUSE(mp);
4205812c3ccSTomohiro Kusumi 	struct fuse_ipc *fip;
4215812c3ccSTomohiro Kusumi 	struct fuse_statfs_out *fso;
4225812c3ccSTomohiro Kusumi 	int error;
4235812c3ccSTomohiro Kusumi 
4245812c3ccSTomohiro Kusumi 	fip = fuse_ipc_get(fmp, 0);
4255812c3ccSTomohiro Kusumi 	fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred);
4265812c3ccSTomohiro Kusumi 	error = fuse_ipc_tx(fip);
4275812c3ccSTomohiro Kusumi 	if (error)
4285812c3ccSTomohiro Kusumi 		return error;
4295812c3ccSTomohiro Kusumi 
4305812c3ccSTomohiro Kusumi 	fso = fuse_out_data(fip);
4315812c3ccSTomohiro Kusumi 
4325812c3ccSTomohiro Kusumi 	mtx_lock(&fmp->mnt_lock);
4335812c3ccSTomohiro Kusumi 	sbp->f_bsize = fso->st.frsize;
4345812c3ccSTomohiro Kusumi 	sbp->f_frsize = FUSE_BLKSIZE;
4355812c3ccSTomohiro Kusumi 	sbp->f_blocks = fso->st.blocks;
4365812c3ccSTomohiro Kusumi 	sbp->f_bfree = fso->st.bfree;
4375812c3ccSTomohiro Kusumi 	sbp->f_bavail = fso->st.bavail;
4385812c3ccSTomohiro Kusumi 	sbp->f_files = fso->st.files;
4395812c3ccSTomohiro Kusumi 	sbp->f_ffree = fso->st.ffree;
4405812c3ccSTomohiro Kusumi 	mtx_unlock(&fmp->mnt_lock);
4415812c3ccSTomohiro Kusumi 
4425812c3ccSTomohiro Kusumi 	fuse_ipc_put(fip);
4435812c3ccSTomohiro Kusumi 
4445812c3ccSTomohiro Kusumi 	return 0;
4455812c3ccSTomohiro Kusumi }
4465812c3ccSTomohiro Kusumi 
4475812c3ccSTomohiro Kusumi static int
fuse_init(struct vfsconf * vfsp)4485812c3ccSTomohiro Kusumi fuse_init(struct vfsconf *vfsp)
4495812c3ccSTomohiro Kusumi {
4505812c3ccSTomohiro Kusumi 	int error;
4515812c3ccSTomohiro Kusumi 
4525812c3ccSTomohiro Kusumi 	fuse_node_init();
4535812c3ccSTomohiro Kusumi 	fuse_ipc_init();
4545812c3ccSTomohiro Kusumi 
4555812c3ccSTomohiro Kusumi 	error = fuse_device_init();
4565812c3ccSTomohiro Kusumi 	if (error) {
4575812c3ccSTomohiro Kusumi 		fuse_ipc_cleanup();
4585812c3ccSTomohiro Kusumi 		fuse_node_cleanup();
4595812c3ccSTomohiro Kusumi 		return error;
4605812c3ccSTomohiro Kusumi 	}
4615812c3ccSTomohiro Kusumi 
4625812c3ccSTomohiro Kusumi 	fuse_print("FUSE ABI %d.%d\n", FUSE_KERNEL_VERSION,
4635812c3ccSTomohiro Kusumi 	    FUSE_KERNEL_MINOR_VERSION);
4645812c3ccSTomohiro Kusumi 
4655812c3ccSTomohiro Kusumi 	return 0;
4665812c3ccSTomohiro Kusumi }
4675812c3ccSTomohiro Kusumi 
4685812c3ccSTomohiro Kusumi static int
fuse_uninit(struct vfsconf * vfsp)4695812c3ccSTomohiro Kusumi fuse_uninit(struct vfsconf *vfsp)
4705812c3ccSTomohiro Kusumi {
4715812c3ccSTomohiro Kusumi 	fuse_ipc_cleanup();
4725812c3ccSTomohiro Kusumi 	fuse_node_cleanup();
4735812c3ccSTomohiro Kusumi 	fuse_device_cleanup();
4745812c3ccSTomohiro Kusumi 
4755812c3ccSTomohiro Kusumi 	return 0;
4765812c3ccSTomohiro Kusumi }
4775812c3ccSTomohiro Kusumi 
4785812c3ccSTomohiro Kusumi static struct vfsops fuse_vfsops = {
47900369c4aSMatthew Dillon 	.vfs_flags = 0,
4805812c3ccSTomohiro Kusumi 	.vfs_init = fuse_init,
4815812c3ccSTomohiro Kusumi 	.vfs_uninit = fuse_uninit,
4825812c3ccSTomohiro Kusumi 	.vfs_mount = fuse_mount,
4835812c3ccSTomohiro Kusumi 	.vfs_unmount = fuse_unmount,
4845d0d0bafSMatthew Dillon 	.vfs_sync = fuse_sync,
4855812c3ccSTomohiro Kusumi 	.vfs_root = fuse_root,
4865812c3ccSTomohiro Kusumi 	.vfs_statfs = fuse_statfs,
4875812c3ccSTomohiro Kusumi 	.vfs_statvfs = fuse_statvfs,
4885812c3ccSTomohiro Kusumi };
4895812c3ccSTomohiro Kusumi 
4905812c3ccSTomohiro Kusumi VFS_SET(fuse_vfsops, fuse, VFCF_SYNTHETIC | VFCF_MPSAFE);
4915812c3ccSTomohiro Kusumi MODULE_VERSION(fuse, 1);
492