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