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