1331722Seadler/* 2241519Sattilio * Copyright (c) 2007-2009 Google Inc. and Amit Singh 3241519Sattilio * All rights reserved. 4241519Sattilio * 5241519Sattilio * Redistribution and use in source and binary forms, with or without 6241519Sattilio * modification, are permitted provided that the following conditions are 7241519Sattilio * met: 8241519Sattilio * 9241519Sattilio * * Redistributions of source code must retain the above copyright 10241519Sattilio * notice, this list of conditions and the following disclaimer. 11241519Sattilio * * Redistributions in binary form must reproduce the above 12241519Sattilio * copyright notice, this list of conditions and the following disclaimer 13241519Sattilio * in the documentation and/or other materials provided with the 14241519Sattilio * distribution. 15241519Sattilio * * Neither the name of Google Inc. nor the names of its 16241519Sattilio * contributors may be used to endorse or promote products derived from 17241519Sattilio * this software without specific prior written permission. 18241519Sattilio * 19241519Sattilio * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20241519Sattilio * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21241519Sattilio * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22241519Sattilio * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23241519Sattilio * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24241519Sattilio * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25241519Sattilio * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26241519Sattilio * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27241519Sattilio * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28241519Sattilio * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29241519Sattilio * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30241519Sattilio * 31241519Sattilio * Copyright (C) 2005 Csaba Henk. 32241519Sattilio * All rights reserved. 33241519Sattilio * 34241519Sattilio * Redistribution and use in source and binary forms, with or without 35241519Sattilio * modification, are permitted provided that the following conditions 36241519Sattilio * are met: 37241519Sattilio * 1. Redistributions of source code must retain the above copyright 38241519Sattilio * notice, this list of conditions and the following disclaimer. 39241519Sattilio * 2. Redistributions in binary form must reproduce the above copyright 40241519Sattilio * notice, this list of conditions and the following disclaimer in the 41241519Sattilio * documentation and/or other materials provided with the distribution. 42241519Sattilio * 43241519Sattilio * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 44241519Sattilio * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45241519Sattilio * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46241519Sattilio * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 47241519Sattilio * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48241519Sattilio * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49241519Sattilio * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50241519Sattilio * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51241519Sattilio * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52241519Sattilio * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53241519Sattilio * SUCH DAMAGE. 54241519Sattilio */ 55241519Sattilio 56241519Sattilio#include <sys/cdefs.h> 57241519Sattilio__FBSDID("$FreeBSD: stable/11/sys/fs/fuse/fuse_vfsops.c 347482 2019-05-11 03:41:58Z asomers $"); 58241519Sattilio 59241519Sattilio#include <sys/types.h> 60241519Sattilio#include <sys/module.h> 61241519Sattilio#include <sys/systm.h> 62241519Sattilio#include <sys/errno.h> 63241519Sattilio#include <sys/param.h> 64241519Sattilio#include <sys/kernel.h> 65263233Srwatson#include <sys/capsicum.h> 66241519Sattilio#include <sys/conf.h> 67241519Sattilio#include <sys/filedesc.h> 68241519Sattilio#include <sys/uio.h> 69241519Sattilio#include <sys/malloc.h> 70241519Sattilio#include <sys/queue.h> 71241519Sattilio#include <sys/lock.h> 72241519Sattilio#include <sys/sx.h> 73241519Sattilio#include <sys/mutex.h> 74241519Sattilio#include <sys/proc.h> 75241519Sattilio#include <sys/vnode.h> 76241519Sattilio#include <sys/namei.h> 77241519Sattilio#include <sys/mount.h> 78241519Sattilio#include <sys/sysctl.h> 79241519Sattilio#include <sys/fcntl.h> 80241519Sattilio 81241519Sattilio#include "fuse.h" 82241519Sattilio#include "fuse_param.h" 83241519Sattilio#include "fuse_node.h" 84241519Sattilio#include "fuse_ipc.h" 85241519Sattilio#include "fuse_internal.h" 86241519Sattilio 87241519Sattilio#include <sys/priv.h> 88241519Sattilio#include <security/mac/mac_framework.h> 89241519Sattilio 90241519Sattilio#define FUSE_DEBUG_MODULE VFSOPS 91241519Sattilio#include "fuse_debug.h" 92241519Sattilio 93241519Sattilio/* This will do for privilege types for now */ 94241519Sattilio#ifndef PRIV_VFS_FUSE_ALLOWOTHER 95241519Sattilio#define PRIV_VFS_FUSE_ALLOWOTHER PRIV_VFS_MOUNT_NONUSER 96241519Sattilio#endif 97241519Sattilio#ifndef PRIV_VFS_FUSE_MOUNT_NONUSER 98241519Sattilio#define PRIV_VFS_FUSE_MOUNT_NONUSER PRIV_VFS_MOUNT_NONUSER 99241519Sattilio#endif 100241519Sattilio#ifndef PRIV_VFS_FUSE_SYNC_UNMOUNT 101241519Sattilio#define PRIV_VFS_FUSE_SYNC_UNMOUNT PRIV_VFS_MOUNT_NONUSER 102241519Sattilio#endif 103241519Sattilio 104241519Sattiliostatic vfs_mount_t fuse_vfsop_mount; 105241519Sattiliostatic vfs_unmount_t fuse_vfsop_unmount; 106241519Sattiliostatic vfs_root_t fuse_vfsop_root; 107241519Sattiliostatic vfs_statfs_t fuse_vfsop_statfs; 108241519Sattilio 109241519Sattiliostruct vfsops fuse_vfsops = { 110241519Sattilio .vfs_mount = fuse_vfsop_mount, 111241519Sattilio .vfs_unmount = fuse_vfsop_unmount, 112241519Sattilio .vfs_root = fuse_vfsop_root, 113241519Sattilio .vfs_statfs = fuse_vfsop_statfs, 114241519Sattilio}; 115241519Sattilio 116241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, init_backgrounded, CTLFLAG_RD, 117273377Shselasky SYSCTL_NULL_INT_PTR, 1, "indicate async handshake"); 118241519Sattiliostatic int fuse_enforce_dev_perms = 0; 119241519Sattilio 120273377ShselaskySYSCTL_INT(_vfs_fuse, OID_AUTO, enforce_dev_perms, CTLFLAG_RW, 121241519Sattilio &fuse_enforce_dev_perms, 0, 122241519Sattilio "enforce fuse device permissions for secondary mounts"); 123241519Sattiliostatic unsigned sync_unmount = 1; 124241519Sattilio 125241519SattilioSYSCTL_UINT(_vfs_fuse, OID_AUTO, sync_unmount, CTLFLAG_RW, 126241519Sattilio &sync_unmount, 0, "specify when to use synchronous unmount"); 127241519Sattilio 128241519SattilioMALLOC_DEFINE(M_FUSEVFS, "fuse_filesystem", "buffer for fuse vfs layer"); 129241519Sattilio 130241519Sattiliostatic int 131241519Sattiliofuse_getdevice(const char *fspec, struct thread *td, struct cdev **fdevp) 132241519Sattilio{ 133241519Sattilio struct nameidata nd, *ndp = &nd; 134241519Sattilio struct vnode *devvp; 135241519Sattilio struct cdev *fdev; 136241519Sattilio int err; 137241519Sattilio 138241519Sattilio /* 139241519Sattilio * Not an update, or updating the name: look up the name 140241519Sattilio * and verify that it refers to a sensible disk device. 141241519Sattilio */ 142241519Sattilio 143241519Sattilio NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td); 144241519Sattilio if ((err = namei(ndp)) != 0) 145241519Sattilio return err; 146241519Sattilio NDFREE(ndp, NDF_ONLY_PNBUF); 147241519Sattilio devvp = ndp->ni_vp; 148241519Sattilio 149241519Sattilio if (devvp->v_type != VCHR) { 150241519Sattilio vrele(devvp); 151241519Sattilio return ENXIO; 152241519Sattilio } 153241519Sattilio fdev = devvp->v_rdev; 154241519Sattilio dev_ref(fdev); 155241519Sattilio 156241519Sattilio if (fuse_enforce_dev_perms) { 157241519Sattilio /* 158241519Sattilio * Check if mounter can open the fuse device. 159241519Sattilio * 160241519Sattilio * This has significance only if we are doing a secondary mount 161241519Sattilio * which doesn't involve actually opening fuse devices, but we 162241519Sattilio * still want to enforce the permissions of the device (in 163241519Sattilio * order to keep control over the circle of fuse users). 164241519Sattilio * 165241519Sattilio * (In case of primary mounts, we are either the superuser so 166241519Sattilio * we can do anything anyway, or we can mount only if the 167241519Sattilio * device is already opened by us, ie. we are permitted to open 168241519Sattilio * the device.) 169241519Sattilio */ 170241519Sattilio#if 0 171241519Sattilio#ifdef MAC 172241519Sattilio err = mac_check_vnode_open(td->td_ucred, devvp, VREAD | VWRITE); 173241519Sattilio if (!err) 174241519Sattilio#endif 175241519Sattilio#endif /* 0 */ 176241519Sattilio err = VOP_ACCESS(devvp, VREAD | VWRITE, td->td_ucred, td); 177241519Sattilio if (err) { 178241519Sattilio vrele(devvp); 179241519Sattilio dev_rel(fdev); 180241519Sattilio return err; 181241519Sattilio } 182241519Sattilio } 183241519Sattilio /* 184241519Sattilio * according to coda code, no extra lock is needed -- 185241519Sattilio * although in sys/vnode.h this field is marked "v" 186241519Sattilio */ 187241519Sattilio vrele(devvp); 188241519Sattilio 189241519Sattilio if (!fdev->si_devsw || 190241519Sattilio strcmp("fuse", fdev->si_devsw->d_name)) { 191241519Sattilio dev_rel(fdev); 192241519Sattilio return ENXIO; 193241519Sattilio } 194241519Sattilio *fdevp = fdev; 195241519Sattilio 196241519Sattilio return 0; 197241519Sattilio} 198241519Sattilio 199241519Sattilio#define FUSE_FLAGOPT(fnam, fval) do { \ 200241519Sattilio vfs_flagopt(opts, #fnam, &mntopts, fval); \ 201241519Sattilio vfs_flagopt(opts, "__" #fnam, &__mntopts, fval); \ 202241519Sattilio} while (0) 203241519Sattilio 204241519Sattiliostatic int 205241519Sattiliofuse_vfsop_mount(struct mount *mp) 206241519Sattilio{ 207241519Sattilio int err; 208241519Sattilio 209241519Sattilio uint64_t mntopts, __mntopts; 210241519Sattilio int max_read_set; 211241519Sattilio uint32_t max_read; 212241519Sattilio int daemon_timeout; 213241519Sattilio int fd; 214241519Sattilio 215241519Sattilio size_t len; 216241519Sattilio 217241519Sattilio struct cdev *fdev; 218347482Sasomers struct fuse_data *data = NULL; 219241519Sattilio struct thread *td; 220241519Sattilio struct file *fp, *fptmp; 221241519Sattilio char *fspec, *subtype; 222241519Sattilio struct vfsoptlist *opts; 223255219Spjd cap_rights_t rights; 224241519Sattilio 225241519Sattilio subtype = NULL; 226241519Sattilio max_read_set = 0; 227241519Sattilio max_read = ~0; 228241519Sattilio err = 0; 229241519Sattilio mntopts = 0; 230241519Sattilio __mntopts = 0; 231241519Sattilio td = curthread; 232241519Sattilio 233241519Sattilio fuse_trace_printf_vfsop(); 234241519Sattilio 235241519Sattilio if (mp->mnt_flag & MNT_UPDATE) 236241519Sattilio return EOPNOTSUPP; 237241519Sattilio 238242875Sattilio MNT_ILOCK(mp); 239241519Sattilio mp->mnt_flag |= MNT_SYNCHRONOUS; 240241519Sattilio mp->mnt_data = NULL; 241242875Sattilio MNT_IUNLOCK(mp); 242241519Sattilio /* Get the new options passed to mount */ 243241519Sattilio opts = mp->mnt_optnew; 244241519Sattilio 245241519Sattilio if (!opts) 246241519Sattilio return EINVAL; 247241519Sattilio 248241519Sattilio /* `fspath' contains the mount point (eg. /mnt/fuse/sshfs); REQUIRED */ 249241519Sattilio if (!vfs_getopts(opts, "fspath", &err)) 250241519Sattilio return err; 251241519Sattilio 252241519Sattilio /* `from' contains the device name (eg. /dev/fuse0); REQUIRED */ 253241519Sattilio fspec = vfs_getopts(opts, "from", &err); 254241519Sattilio if (!fspec) 255241519Sattilio return err; 256241519Sattilio 257241519Sattilio /* `fd' contains the filedescriptor for this session; REQUIRED */ 258241519Sattilio if (vfs_scanopt(opts, "fd", "%d", &fd) != 1) 259241519Sattilio return EINVAL; 260241519Sattilio 261241519Sattilio err = fuse_getdevice(fspec, td, &fdev); 262241519Sattilio if (err != 0) 263241519Sattilio return err; 264241519Sattilio 265241519Sattilio /* 266241519Sattilio * With the help of underscored options the mount program 267241519Sattilio * can inform us from the flags it sets by default 268241519Sattilio */ 269241519Sattilio FUSE_FLAGOPT(allow_other, FSESS_DAEMON_CAN_SPY); 270241519Sattilio FUSE_FLAGOPT(push_symlinks_in, FSESS_PUSH_SYMLINKS_IN); 271241519Sattilio FUSE_FLAGOPT(default_permissions, FSESS_DEFAULT_PERMISSIONS); 272241519Sattilio FUSE_FLAGOPT(no_attrcache, FSESS_NO_ATTRCACHE); 273241519Sattilio FUSE_FLAGOPT(no_readahed, FSESS_NO_READAHEAD); 274241519Sattilio FUSE_FLAGOPT(no_datacache, FSESS_NO_DATACACHE); 275241519Sattilio FUSE_FLAGOPT(no_namecache, FSESS_NO_NAMECACHE); 276241519Sattilio FUSE_FLAGOPT(no_mmap, FSESS_NO_MMAP); 277241519Sattilio FUSE_FLAGOPT(brokenio, FSESS_BROKENIO); 278241519Sattilio 279241519Sattilio if (vfs_scanopt(opts, "max_read=", "%u", &max_read) == 1) 280241519Sattilio max_read_set = 1; 281241519Sattilio if (vfs_scanopt(opts, "timeout=", "%u", &daemon_timeout) == 1) { 282241519Sattilio if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT) 283241519Sattilio daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT; 284241519Sattilio else if (daemon_timeout > FUSE_MAX_DAEMON_TIMEOUT) 285241519Sattilio daemon_timeout = FUSE_MAX_DAEMON_TIMEOUT; 286241519Sattilio } else { 287241519Sattilio daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT; 288241519Sattilio } 289241519Sattilio subtype = vfs_getopts(opts, "subtype=", &err); 290241519Sattilio 291241521Sattilio FS_DEBUG2G("mntopts 0x%jx\n", (uintmax_t)mntopts); 292241519Sattilio 293255219Spjd err = fget(td, fd, cap_rights_init(&rights, CAP_READ), &fp); 294241519Sattilio if (err != 0) { 295241521Sattilio FS_DEBUG("invalid or not opened device: data=%p\n", data); 296241519Sattilio goto out; 297241519Sattilio } 298241519Sattilio fptmp = td->td_fpop; 299241519Sattilio td->td_fpop = fp; 300241519Sattilio err = devfs_get_cdevpriv((void **)&data); 301241519Sattilio td->td_fpop = fptmp; 302241519Sattilio fdrop(fp, td); 303241519Sattilio FUSE_LOCK(); 304241519Sattilio if (err != 0 || data == NULL || data->mp != NULL) { 305241521Sattilio FS_DEBUG("invalid or not opened device: data=%p data.mp=%p\n", 306241519Sattilio data, data != NULL ? data->mp : NULL); 307241519Sattilio err = ENXIO; 308241519Sattilio FUSE_UNLOCK(); 309241519Sattilio goto out; 310241519Sattilio } 311241519Sattilio if (fdata_get_dead(data)) { 312241521Sattilio FS_DEBUG("device is dead during mount: data=%p\n", data); 313241519Sattilio err = ENOTCONN; 314241519Sattilio FUSE_UNLOCK(); 315241519Sattilio goto out; 316241519Sattilio } 317241519Sattilio /* Sanity + permission checks */ 318241519Sattilio if (!data->daemoncred) 319241519Sattilio panic("fuse daemon found, but identity unknown"); 320241519Sattilio if (mntopts & FSESS_DAEMON_CAN_SPY) 321241519Sattilio err = priv_check(td, PRIV_VFS_FUSE_ALLOWOTHER); 322241519Sattilio if (err == 0 && td->td_ucred->cr_uid != data->daemoncred->cr_uid) 323241519Sattilio /* are we allowed to do the first mount? */ 324241519Sattilio err = priv_check(td, PRIV_VFS_FUSE_MOUNT_NONUSER); 325241519Sattilio if (err) { 326241519Sattilio FUSE_UNLOCK(); 327241519Sattilio goto out; 328241519Sattilio } 329241519Sattilio data->ref++; 330241519Sattilio data->mp = mp; 331241519Sattilio data->dataflags |= mntopts; 332241519Sattilio data->max_read = max_read; 333241519Sattilio data->daemon_timeout = daemon_timeout; 334241519Sattilio FUSE_UNLOCK(); 335241519Sattilio 336241519Sattilio vfs_getnewfsid(mp); 337242875Sattilio MNT_ILOCK(mp); 338242875Sattilio mp->mnt_data = data; 339241519Sattilio mp->mnt_flag |= MNT_LOCAL; 340281562Srmacklem mp->mnt_kern_flag |= MNTK_USES_BCACHE; 341242875Sattilio MNT_IUNLOCK(mp); 342242875Sattilio /* We need this here as this slot is used by getnewvnode() */ 343242875Sattilio mp->mnt_stat.f_iosize = PAGE_SIZE; 344241519Sattilio if (subtype) { 345241519Sattilio strlcat(mp->mnt_stat.f_fstypename, ".", MFSNAMELEN); 346241519Sattilio strlcat(mp->mnt_stat.f_fstypename, subtype, MFSNAMELEN); 347241519Sattilio } 348241519Sattilio copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len); 349241519Sattilio bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len); 350241521Sattilio FS_DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname); 351241519Sattilio 352241519Sattilio /* Now handshaking with daemon */ 353241519Sattilio fuse_internal_send_init(data, td); 354241519Sattilio 355241519Sattilioout: 356241519Sattilio if (err) { 357241519Sattilio FUSE_LOCK(); 358347482Sasomers if (data != NULL && data->mp == mp) { 359241519Sattilio /* 360241519Sattilio * Destroy device only if we acquired reference to 361241519Sattilio * it 362241519Sattilio */ 363241521Sattilio FS_DEBUG("mount failed, destroy device: data=%p mp=%p" 364241519Sattilio " err=%d\n", 365241519Sattilio data, mp, err); 366241519Sattilio data->mp = NULL; 367241519Sattilio fdata_trydestroy(data); 368241519Sattilio } 369241519Sattilio FUSE_UNLOCK(); 370241519Sattilio dev_rel(fdev); 371241519Sattilio } 372241519Sattilio return err; 373241519Sattilio} 374241519Sattilio 375241519Sattiliostatic int 376241519Sattiliofuse_vfsop_unmount(struct mount *mp, int mntflags) 377241519Sattilio{ 378241519Sattilio int err = 0; 379241519Sattilio int flags = 0; 380241519Sattilio 381241519Sattilio struct cdev *fdev; 382241519Sattilio struct fuse_data *data; 383241519Sattilio struct fuse_dispatcher fdi; 384241519Sattilio struct thread *td = curthread; 385241519Sattilio 386241519Sattilio fuse_trace_printf_vfsop(); 387241519Sattilio 388241519Sattilio if (mntflags & MNT_FORCE) { 389241519Sattilio flags |= FORCECLOSE; 390241519Sattilio } 391241519Sattilio data = fuse_get_mpdata(mp); 392241519Sattilio if (!data) { 393241519Sattilio panic("no private data for mount point?"); 394241519Sattilio } 395241519Sattilio /* There is 1 extra root vnode reference (mp->mnt_data). */ 396241519Sattilio FUSE_LOCK(); 397241519Sattilio if (data->vroot != NULL) { 398241519Sattilio struct vnode *vroot = data->vroot; 399241519Sattilio 400241519Sattilio data->vroot = NULL; 401241519Sattilio FUSE_UNLOCK(); 402241519Sattilio vrele(vroot); 403241519Sattilio } else 404241519Sattilio FUSE_UNLOCK(); 405241519Sattilio err = vflush(mp, 0, flags, td); 406241519Sattilio if (err) { 407241519Sattilio debug_printf("vflush failed"); 408241519Sattilio return err; 409241519Sattilio } 410241519Sattilio if (fdata_get_dead(data)) { 411241519Sattilio goto alreadydead; 412241519Sattilio } 413241519Sattilio fdisp_init(&fdi, 0); 414241519Sattilio fdisp_make(&fdi, FUSE_DESTROY, mp, 0, td, NULL); 415241519Sattilio 416241519Sattilio err = fdisp_wait_answ(&fdi); 417241519Sattilio fdisp_destroy(&fdi); 418241519Sattilio 419241519Sattilio fdata_set_dead(data); 420241519Sattilio 421241519Sattilioalreadydead: 422241519Sattilio FUSE_LOCK(); 423241519Sattilio data->mp = NULL; 424241519Sattilio fdev = data->fdev; 425241519Sattilio fdata_trydestroy(data); 426241519Sattilio FUSE_UNLOCK(); 427241519Sattilio 428241519Sattilio MNT_ILOCK(mp); 429241519Sattilio mp->mnt_data = NULL; 430241519Sattilio mp->mnt_flag &= ~MNT_LOCAL; 431241519Sattilio MNT_IUNLOCK(mp); 432241519Sattilio 433241519Sattilio dev_rel(fdev); 434241519Sattilio 435241519Sattilio return 0; 436241519Sattilio} 437241519Sattilio 438241519Sattiliostatic int 439241519Sattiliofuse_vfsop_root(struct mount *mp, int lkflags, struct vnode **vpp) 440241519Sattilio{ 441241519Sattilio struct fuse_data *data = fuse_get_mpdata(mp); 442241519Sattilio int err = 0; 443241519Sattilio 444241519Sattilio if (data->vroot != NULL) { 445241519Sattilio err = vget(data->vroot, lkflags, curthread); 446241519Sattilio if (err == 0) 447241519Sattilio *vpp = data->vroot; 448241519Sattilio } else { 449241519Sattilio err = fuse_vnode_get(mp, FUSE_ROOT_ID, NULL, vpp, NULL, VDIR); 450241519Sattilio if (err == 0) { 451241519Sattilio FUSE_LOCK(); 452241519Sattilio MPASS(data->vroot == NULL || data->vroot == *vpp); 453241519Sattilio if (data->vroot == NULL) { 454241521Sattilio FS_DEBUG("new root vnode\n"); 455241519Sattilio data->vroot = *vpp; 456241519Sattilio FUSE_UNLOCK(); 457241519Sattilio vref(*vpp); 458241519Sattilio } else if (data->vroot != *vpp) { 459241521Sattilio FS_DEBUG("root vnode race\n"); 460241519Sattilio FUSE_UNLOCK(); 461241519Sattilio VOP_UNLOCK(*vpp, 0); 462241519Sattilio vrele(*vpp); 463241519Sattilio vrecycle(*vpp); 464241519Sattilio *vpp = data->vroot; 465241519Sattilio } else 466241519Sattilio FUSE_UNLOCK(); 467241519Sattilio } 468241519Sattilio } 469241519Sattilio return err; 470241519Sattilio} 471241519Sattilio 472241519Sattiliostatic int 473241519Sattiliofuse_vfsop_statfs(struct mount *mp, struct statfs *sbp) 474241519Sattilio{ 475241519Sattilio struct fuse_dispatcher fdi; 476241519Sattilio int err = 0; 477241519Sattilio 478241519Sattilio struct fuse_statfs_out *fsfo; 479241519Sattilio struct fuse_data *data; 480241519Sattilio 481241521Sattilio FS_DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname); 482241519Sattilio data = fuse_get_mpdata(mp); 483241519Sattilio 484241519Sattilio if (!(data->dataflags & FSESS_INITED)) 485241519Sattilio goto fake; 486241519Sattilio 487241519Sattilio fdisp_init(&fdi, 0); 488241519Sattilio fdisp_make(&fdi, FUSE_STATFS, mp, FUSE_ROOT_ID, NULL, NULL); 489241519Sattilio err = fdisp_wait_answ(&fdi); 490241519Sattilio if (err) { 491241519Sattilio fdisp_destroy(&fdi); 492241519Sattilio if (err == ENOTCONN) { 493241519Sattilio /* 494241519Sattilio * We want to seem a legitimate fs even if the daemon 495241519Sattilio * is stiff dead... (so that, eg., we can still do path 496241519Sattilio * based unmounting after the daemon dies). 497241519Sattilio */ 498241519Sattilio goto fake; 499241519Sattilio } 500241519Sattilio return err; 501241519Sattilio } 502241519Sattilio fsfo = fdi.answ; 503241519Sattilio 504241519Sattilio sbp->f_blocks = fsfo->st.blocks; 505241519Sattilio sbp->f_bfree = fsfo->st.bfree; 506241519Sattilio sbp->f_bavail = fsfo->st.bavail; 507241519Sattilio sbp->f_files = fsfo->st.files; 508241519Sattilio sbp->f_ffree = fsfo->st.ffree; /* cast from uint64_t to int64_t */ 509241519Sattilio sbp->f_namemax = fsfo->st.namelen; 510241519Sattilio sbp->f_bsize = fsfo->st.frsize; /* cast from uint32_t to uint64_t */ 511241519Sattilio 512241521Sattilio FS_DEBUG("fuse_statfs_out -- blocks: %llu, bfree: %llu, bavail: %llu, " 513241519Sattilio "fil es: %llu, ffree: %llu, bsize: %i, namelen: %i\n", 514241519Sattilio (unsigned long long)fsfo->st.blocks, 515241519Sattilio (unsigned long long)fsfo->st.bfree, 516241519Sattilio (unsigned long long)fsfo->st.bavail, 517241519Sattilio (unsigned long long)fsfo->st.files, 518241519Sattilio (unsigned long long)fsfo->st.ffree, fsfo->st.bsize, 519241519Sattilio fsfo->st.namelen); 520241519Sattilio 521241519Sattilio fdisp_destroy(&fdi); 522241519Sattilio return 0; 523241519Sattilio 524241519Sattiliofake: 525241519Sattilio sbp->f_blocks = 0; 526241519Sattilio sbp->f_bfree = 0; 527241519Sattilio sbp->f_bavail = 0; 528241519Sattilio sbp->f_files = 0; 529241519Sattilio sbp->f_ffree = 0; 530241519Sattilio sbp->f_namemax = 0; 531241519Sattilio sbp->f_bsize = FUSE_DEFAULT_BLOCKSIZE; 532241519Sattilio 533241519Sattilio return 0; 534241519Sattilio} 535