xref: /freebsd-src/sys/fs/fuse/fuse_file.c (revision f0f596bd955e5b48c55db502e79fc652ac8970d3)
151369649SPedro F. Giffuni /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
45fe58019SAttilio Rao  * Copyright (c) 2007-2009 Google Inc. and Amit Singh
55fe58019SAttilio Rao  * All rights reserved.
65fe58019SAttilio Rao  *
75fe58019SAttilio Rao  * Redistribution and use in source and binary forms, with or without
85fe58019SAttilio Rao  * modification, are permitted provided that the following conditions are
95fe58019SAttilio Rao  * met:
105fe58019SAttilio Rao  *
115fe58019SAttilio Rao  * * Redistributions of source code must retain the above copyright
125fe58019SAttilio Rao  *   notice, this list of conditions and the following disclaimer.
135fe58019SAttilio Rao  * * Redistributions in binary form must reproduce the above
145fe58019SAttilio Rao  *   copyright notice, this list of conditions and the following disclaimer
155fe58019SAttilio Rao  *   in the documentation and/or other materials provided with the
165fe58019SAttilio Rao  *   distribution.
175fe58019SAttilio Rao  * * Neither the name of Google Inc. nor the names of its
185fe58019SAttilio Rao  *   contributors may be used to endorse or promote products derived from
195fe58019SAttilio Rao  *   this software without specific prior written permission.
205fe58019SAttilio Rao  *
215fe58019SAttilio Rao  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225fe58019SAttilio Rao  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
235fe58019SAttilio Rao  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
245fe58019SAttilio Rao  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
255fe58019SAttilio Rao  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
265fe58019SAttilio Rao  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
275fe58019SAttilio Rao  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
285fe58019SAttilio Rao  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
295fe58019SAttilio Rao  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
305fe58019SAttilio Rao  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
315fe58019SAttilio Rao  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
325fe58019SAttilio Rao  *
335fe58019SAttilio Rao  * Copyright (C) 2005 Csaba Henk.
345fe58019SAttilio Rao  * All rights reserved.
355fe58019SAttilio Rao  *
368aafc8c3SAlan Somers  * Copyright (c) 2019 The FreeBSD Foundation
378aafc8c3SAlan Somers  *
388aafc8c3SAlan Somers  * Portions of this software were developed by BFF Storage Systems, LLC under
398aafc8c3SAlan Somers  * sponsorship from the FreeBSD Foundation.
408aafc8c3SAlan Somers  *
415fe58019SAttilio Rao  * Redistribution and use in source and binary forms, with or without
425fe58019SAttilio Rao  * modification, are permitted provided that the following conditions
435fe58019SAttilio Rao  * are met:
445fe58019SAttilio Rao  * 1. Redistributions of source code must retain the above copyright
455fe58019SAttilio Rao  *    notice, this list of conditions and the following disclaimer.
465fe58019SAttilio Rao  * 2. Redistributions in binary form must reproduce the above copyright
475fe58019SAttilio Rao  *    notice, this list of conditions and the following disclaimer in the
485fe58019SAttilio Rao  *    documentation and/or other materials provided with the distribution.
495fe58019SAttilio Rao  *
505fe58019SAttilio Rao  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
515fe58019SAttilio Rao  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
525fe58019SAttilio Rao  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
535fe58019SAttilio Rao  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
545fe58019SAttilio Rao  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
555fe58019SAttilio Rao  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
565fe58019SAttilio Rao  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
575fe58019SAttilio Rao  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
585fe58019SAttilio Rao  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
595fe58019SAttilio Rao  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
605fe58019SAttilio Rao  * SUCH DAMAGE.
615fe58019SAttilio Rao  */
625fe58019SAttilio Rao 
63cf169498SAlan Somers #include <sys/param.h>
6407e86257SAlan Somers #include <sys/systm.h>
65560a55d0SAlan Somers #include <sys/counter.h>
665fe58019SAttilio Rao #include <sys/module.h>
675fe58019SAttilio Rao #include <sys/errno.h>
685fe58019SAttilio Rao #include <sys/kernel.h>
695fe58019SAttilio Rao #include <sys/conf.h>
705fe58019SAttilio Rao #include <sys/uio.h>
715fe58019SAttilio Rao #include <sys/malloc.h>
725fe58019SAttilio Rao #include <sys/queue.h>
735fe58019SAttilio Rao #include <sys/lock.h>
745fe58019SAttilio Rao #include <sys/sx.h>
755fe58019SAttilio Rao #include <sys/mutex.h>
765fe58019SAttilio Rao #include <sys/proc.h>
775fe58019SAttilio Rao #include <sys/mount.h>
785fe58019SAttilio Rao #include <sys/vnode.h>
79cf169498SAlan Somers #include <sys/sdt.h>
805fe58019SAttilio Rao #include <sys/sysctl.h>
815fe58019SAttilio Rao 
825fe58019SAttilio Rao #include "fuse.h"
835fe58019SAttilio Rao #include "fuse_file.h"
845fe58019SAttilio Rao #include "fuse_internal.h"
85a7e81cb3SAlan Somers #include "fuse_io.h"
865fe58019SAttilio Rao #include "fuse_ipc.h"
875fe58019SAttilio Rao #include "fuse_node.h"
885fe58019SAttilio Rao 
891cedd6dfSAlan Somers MALLOC_DEFINE(M_FUSE_FILEHANDLE, "fuse_filefilehandle", "FUSE file handle");
901cedd6dfSAlan Somers 
91419e7ff6SAlan Somers SDT_PROVIDER_DECLARE(fusefs);
92cf169498SAlan Somers /*
93cf169498SAlan Somers  * Fuse trace probe:
94cf169498SAlan Somers  * arg0: verbosity.  Higher numbers give more verbose messages
95cf169498SAlan Somers  * arg1: Textual message
96cf169498SAlan Somers  */
97419e7ff6SAlan Somers SDT_PROBE_DEFINE2(fusefs, , file, trace, "int", "char*");
985fe58019SAttilio Rao 
9938c86346SAlan Somers static counter_u64_t fuse_fh_count;
1005fe58019SAttilio Rao 
101560a55d0SAlan Somers SYSCTL_COUNTER_U64(_vfs_fusefs_stats, OID_AUTO, filehandle_count, CTLFLAG_RD,
102560a55d0SAlan Somers     &fuse_fh_count, "number of open FUSE filehandles");
1035fe58019SAttilio Rao 
1049e444871SAlan Somers /* Get the FUFH type for a particular access mode */
1059e444871SAlan Somers static inline fufh_type_t
1069e444871SAlan Somers fflags_2_fufh_type(int fflags)
1079e444871SAlan Somers {
1089e444871SAlan Somers 	if ((fflags & FREAD) && (fflags & FWRITE))
1099e444871SAlan Somers 		return FUFH_RDWR;
1109e444871SAlan Somers 	else if (fflags & (FWRITE))
1119e444871SAlan Somers 		return FUFH_WRONLY;
1129e444871SAlan Somers 	else if (fflags & (FREAD))
1139e444871SAlan Somers 		return FUFH_RDONLY;
1149e444871SAlan Somers 	else if (fflags & (FEXEC))
1159e444871SAlan Somers 		return FUFH_EXEC;
1169e444871SAlan Somers 	else
1179e444871SAlan Somers 		panic("FUSE: What kind of a flag is this (%x)?", fflags);
1189e444871SAlan Somers }
1199e444871SAlan Somers 
1205fe58019SAttilio Rao int
1219e444871SAlan Somers fuse_filehandle_open(struct vnode *vp, int a_mode,
12202295cafSConrad Meyer     struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred)
1235fe58019SAttilio Rao {
1247124d2bcSAlan Somers 	struct mount *mp = vnode_mount(vp);
1255fe58019SAttilio Rao 	struct fuse_dispatcher fdi;
1267124d2bcSAlan Somers 	const struct fuse_open_out default_foo = {
1277124d2bcSAlan Somers 		.fh = 0,
1287124d2bcSAlan Somers 		.open_flags = FOPEN_KEEP_CACHE,
1297124d2bcSAlan Somers 		.padding = 0
1307124d2bcSAlan Somers 	};
1317124d2bcSAlan Somers 	struct fuse_open_in *foi = NULL;
1327124d2bcSAlan Somers 	const struct fuse_open_out *foo;
1339e444871SAlan Somers 	fufh_type_t fufh_type;
1345fe58019SAttilio Rao 	int err = 0;
1355fe58019SAttilio Rao 	int oflags = 0;
1365fe58019SAttilio Rao 	int op = FUSE_OPEN;
1377124d2bcSAlan Somers 	int relop = FUSE_RELEASE;
1385fe58019SAttilio Rao 
1399e444871SAlan Somers 	fufh_type = fflags_2_fufh_type(a_mode);
1409e444871SAlan Somers 	oflags = fufh_type_2_fflags(fufh_type);
1415fe58019SAttilio Rao 
1425fe58019SAttilio Rao 	if (vnode_isdir(vp)) {
1435fe58019SAttilio Rao 		op = FUSE_OPENDIR;
1447124d2bcSAlan Somers 		relop = FUSE_RELEASEDIR;
145363a7416SAlan Somers 		/* vn_open_vnode already rejects FWRITE on directories */
146363a7416SAlan Somers 		MPASS(fufh_type == FUFH_RDONLY || fufh_type == FUFH_EXEC);
1475fe58019SAttilio Rao 	}
1485fe58019SAttilio Rao 	fdisp_init(&fdi, sizeof(*foi));
149*f0f596bdSCismonX 	if (fsess_not_impl(mp, op)) {
1507124d2bcSAlan Somers 		/* The operation implicitly succeeds */
1517124d2bcSAlan Somers 		foo = &default_foo;
1527124d2bcSAlan Somers 	} else {
1535fe58019SAttilio Rao 		fdisp_make_vp(&fdi, op, vp, td, cred);
1545fe58019SAttilio Rao 
1555fe58019SAttilio Rao 		foi = fdi.indata;
1565fe58019SAttilio Rao 		foi->flags = oflags;
1575fe58019SAttilio Rao 
1587124d2bcSAlan Somers 		err = fdisp_wait_answ(&fdi);
159*f0f596bdSCismonX 		if (err == ENOSYS) {
1607124d2bcSAlan Somers 			/* The operation implicitly succeeds */
1617124d2bcSAlan Somers 			foo = &default_foo;
1627124d2bcSAlan Somers 			fsess_set_notimpl(mp, op);
1637124d2bcSAlan Somers 			fsess_set_notimpl(mp, relop);
1647124d2bcSAlan Somers 			err = 0;
1657124d2bcSAlan Somers 		} else if (err) {
166419e7ff6SAlan Somers 			SDT_PROBE2(fusefs, , file, trace, 1,
167cf169498SAlan Somers 				"OUCH ... daemon didn't give fh");
1687124d2bcSAlan Somers 			if (err == ENOENT)
1695fe58019SAttilio Rao 				fuse_internal_vnode_disappear(vp);
1705fe58019SAttilio Rao 			goto out;
1717124d2bcSAlan Somers 		} else {
1725fe58019SAttilio Rao 			foo = fdi.answ;
173*f0f596bdSCismonX 			fsess_set_impl(mp, op);
1747124d2bcSAlan Somers 		}
1757124d2bcSAlan Somers 	}
1765fe58019SAttilio Rao 
177a7e81cb3SAlan Somers 	fuse_filehandle_init(vp, fufh_type, fufhp, td, cred, foo);
1785fe58019SAttilio Rao 	fuse_vnode_open(vp, foo->open_flags, td);
1795fe58019SAttilio Rao 
1805fe58019SAttilio Rao out:
1817124d2bcSAlan Somers 	if (foi)
1825fe58019SAttilio Rao 		fdisp_destroy(&fdi);
1835fe58019SAttilio Rao 	return err;
1845fe58019SAttilio Rao }
1855fe58019SAttilio Rao 
1865fe58019SAttilio Rao int
1875ec10aa5SAlan Somers fuse_filehandle_close(struct vnode *vp, struct fuse_filehandle *fufh,
18802295cafSConrad Meyer     struct thread *td, struct ucred *cred)
1895fe58019SAttilio Rao {
1907124d2bcSAlan Somers 	struct mount *mp = vnode_mount(vp);
1915fe58019SAttilio Rao 	struct fuse_dispatcher fdi;
1925fe58019SAttilio Rao 	struct fuse_release_in *fri;
1935fe58019SAttilio Rao 
1945fe58019SAttilio Rao 	int err = 0;
1955fe58019SAttilio Rao 	int op = FUSE_RELEASE;
1965fe58019SAttilio Rao 
1975fe58019SAttilio Rao 	if (fuse_isdeadfs(vp)) {
1985fe58019SAttilio Rao 		goto out;
1995fe58019SAttilio Rao 	}
2003dc1c7d6SConrad Meyer 	if (vnode_isdir(vp))
2015fe58019SAttilio Rao 		op = FUSE_RELEASEDIR;
2027124d2bcSAlan Somers 
2037124d2bcSAlan Somers 	if (fsess_not_impl(mp, op))
2047124d2bcSAlan Somers 		goto out;
2057124d2bcSAlan Somers 
2065fe58019SAttilio Rao 	fdisp_init(&fdi, sizeof(*fri));
2075fe58019SAttilio Rao 	fdisp_make_vp(&fdi, op, vp, td, cred);
2085fe58019SAttilio Rao 	fri = fdi.indata;
2095fe58019SAttilio Rao 	fri->fh = fufh->fh_id;
2109e444871SAlan Somers 	fri->flags = fufh_type_2_fflags(fufh->fufh_type);
211f067b609SAlan Somers 	/*
212f067b609SAlan Somers 	 * If the file has a POSIX lock then we're supposed to set lock_owner.
213f067b609SAlan Somers 	 * If not, then lock_owner is undefined.  So we may as well always set
214f067b609SAlan Somers 	 * it.
215f067b609SAlan Somers 	 */
216f067b609SAlan Somers 	fri->lock_owner = td->td_proc->p_pid;
2175fe58019SAttilio Rao 
2185fe58019SAttilio Rao 	err = fdisp_wait_answ(&fdi);
2195fe58019SAttilio Rao 	fdisp_destroy(&fdi);
2205fe58019SAttilio Rao 
2215fe58019SAttilio Rao out:
222560a55d0SAlan Somers 	counter_u64_add(fuse_fh_count, -1);
2231cedd6dfSAlan Somers 	LIST_REMOVE(fufh, next);
2241cedd6dfSAlan Somers 	free(fufh, M_FUSE_FILEHANDLE);
2255fe58019SAttilio Rao 
2265fe58019SAttilio Rao 	return err;
2275fe58019SAttilio Rao }
2285fe58019SAttilio Rao 
229e6e24456SRick Macklem /*
230e6e24456SRick Macklem  * Check for a valid file handle, first the type requested, but if that
231e6e24456SRick Macklem  * isn't valid, try for FUFH_RDWR.
232f8d4af10SAlan Somers  * Return true if there is any file handle with the correct credentials and
233f8d4af10SAlan Somers  * a fufh type that includes the provided one.
234f8d4af10SAlan Somers  * A pid of 0 means "don't care"
235e6e24456SRick Macklem  */
236f8d4af10SAlan Somers bool
2379e444871SAlan Somers fuse_filehandle_validrw(struct vnode *vp, int mode,
238f8d4af10SAlan Somers 	struct ucred *cred, pid_t pid)
2395fe58019SAttilio Rao {
2405fe58019SAttilio Rao 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
2415fe58019SAttilio Rao 	struct fuse_filehandle *fufh;
2429e444871SAlan Somers 	fufh_type_t fufh_type = fflags_2_fufh_type(mode);
2435fe58019SAttilio Rao 
244f8d4af10SAlan Somers 	/*
245f8d4af10SAlan Somers 	 * Unlike fuse_filehandle_get, we want to search for a filehandle with
246f8d4af10SAlan Somers 	 * the exact cred, and no fallback
247f8d4af10SAlan Somers 	 */
248f8d4af10SAlan Somers 	LIST_FOREACH(fufh, &fvdat->handles, next) {
2499e444871SAlan Somers 		if (fufh->fufh_type == fufh_type &&
250f8d4af10SAlan Somers 		    fufh->uid == cred->cr_uid &&
251f8d4af10SAlan Somers 		    fufh->gid == cred->cr_rgid &&
252f8d4af10SAlan Somers 		    (pid == 0 || fufh->pid == pid))
253f8d4af10SAlan Somers 			return true;
254f8d4af10SAlan Somers 	}
255f8d4af10SAlan Somers 
256f8d4af10SAlan Somers 	if (fufh_type == FUFH_EXEC)
257f8d4af10SAlan Somers 		return false;
258f8d4af10SAlan Somers 
259f8d4af10SAlan Somers 	/* Fallback: find a RDWR list entry with the right cred */
260f8d4af10SAlan Somers 	LIST_FOREACH(fufh, &fvdat->handles, next) {
2619e444871SAlan Somers 		if (fufh->fufh_type == FUFH_RDWR &&
262f8d4af10SAlan Somers 		    fufh->uid == cred->cr_uid &&
263f8d4af10SAlan Somers 		    fufh->gid == cred->cr_rgid &&
264f8d4af10SAlan Somers 		    (pid == 0 || fufh->pid == pid))
265f8d4af10SAlan Somers 			return true;
266f8d4af10SAlan Somers 	}
267f8d4af10SAlan Somers 
268f8d4af10SAlan Somers 	return false;
269f8d4af10SAlan Somers }
270f8d4af10SAlan Somers 
271f8d4af10SAlan Somers int
2729f10f423SAlan Somers fuse_filehandle_get(struct vnode *vp, int fflag,
273f8d4af10SAlan Somers     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
274f8d4af10SAlan Somers {
275f8d4af10SAlan Somers 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
276f8d4af10SAlan Somers 	struct fuse_filehandle *fufh;
2779f10f423SAlan Somers 	fufh_type_t fufh_type;
278f8d4af10SAlan Somers 
2799f10f423SAlan Somers 	fufh_type = fflags_2_fufh_type(fflag);
280e76986fdSAlan Somers 	/* cred can be NULL for in-kernel clients */
281f8d4af10SAlan Somers 	if (cred == NULL)
282f8d4af10SAlan Somers 		goto fallback;
283f8d4af10SAlan Somers 
284f8d4af10SAlan Somers 	LIST_FOREACH(fufh, &fvdat->handles, next) {
2859e444871SAlan Somers 		if (fufh->fufh_type == fufh_type &&
286f8d4af10SAlan Somers 		    fufh->uid == cred->cr_uid &&
287f8d4af10SAlan Somers 		    fufh->gid == cred->cr_rgid &&
288f8d4af10SAlan Somers 		    (pid == 0 || fufh->pid == pid))
289f8d4af10SAlan Somers 			goto found;
290f8d4af10SAlan Somers 	}
291f8d4af10SAlan Somers 
292f8d4af10SAlan Somers fallback:
2935ec10aa5SAlan Somers 	/* Fallback: find a list entry with the right flags */
2941cedd6dfSAlan Somers 	LIST_FOREACH(fufh, &fvdat->handles, next) {
2959e444871SAlan Somers 		if (fufh->fufh_type == fufh_type)
2961cedd6dfSAlan Somers 			break;
2971cedd6dfSAlan Somers 	}
2981cedd6dfSAlan Somers 
2991cedd6dfSAlan Somers 	if (fufh == NULL)
3005fe58019SAttilio Rao 		return EBADF;
301f8d4af10SAlan Somers 
302f8d4af10SAlan Somers found:
3035fe58019SAttilio Rao 	if (fufhp != NULL)
3045fe58019SAttilio Rao 		*fufhp = fufh;
3055fe58019SAttilio Rao 	return 0;
3065fe58019SAttilio Rao }
3075fe58019SAttilio Rao 
308f067b609SAlan Somers /* Get a file handle with any kind of flags */
309f067b609SAlan Somers int
310f067b609SAlan Somers fuse_filehandle_get_anyflags(struct vnode *vp,
311f067b609SAlan Somers     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
312f067b609SAlan Somers {
313f067b609SAlan Somers 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
314f067b609SAlan Somers 	struct fuse_filehandle *fufh;
315f067b609SAlan Somers 
316f067b609SAlan Somers 	if (cred == NULL)
317f067b609SAlan Somers 		goto fallback;
318f067b609SAlan Somers 
319f067b609SAlan Somers 	LIST_FOREACH(fufh, &fvdat->handles, next) {
320f067b609SAlan Somers 		if (fufh->uid == cred->cr_uid &&
321f067b609SAlan Somers 		    fufh->gid == cred->cr_rgid &&
322f067b609SAlan Somers 		    (pid == 0 || fufh->pid == pid))
323f067b609SAlan Somers 			goto found;
324f067b609SAlan Somers 	}
325f067b609SAlan Somers 
326f067b609SAlan Somers fallback:
327f067b609SAlan Somers 	/* Fallback: find any list entry */
328f067b609SAlan Somers 	fufh = LIST_FIRST(&fvdat->handles);
329f067b609SAlan Somers 
330f067b609SAlan Somers 	if (fufh == NULL)
331f067b609SAlan Somers 		return EBADF;
332f067b609SAlan Somers 
333f067b609SAlan Somers found:
334f067b609SAlan Somers 	if (fufhp != NULL)
335f067b609SAlan Somers 		*fufhp = fufh;
336f067b609SAlan Somers 	return 0;
337f067b609SAlan Somers }
338f067b609SAlan Somers 
3395fe58019SAttilio Rao int
3409f10f423SAlan Somers fuse_filehandle_getrw(struct vnode *vp, int fflag,
341f8d4af10SAlan Somers     struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
3425fe58019SAttilio Rao {
3431cedd6dfSAlan Somers 	int err;
3445fe58019SAttilio Rao 
3459f10f423SAlan Somers 	err = fuse_filehandle_get(vp, fflag, fufhp, cred, pid);
3461cedd6dfSAlan Somers 	if (err)
3479f10f423SAlan Somers 		err = fuse_filehandle_get(vp, FREAD | FWRITE, fufhp, cred, pid);
3481cedd6dfSAlan Somers 	return err;
3495fe58019SAttilio Rao }
3505fe58019SAttilio Rao 
3515fe58019SAttilio Rao void
35202295cafSConrad Meyer fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
3537124d2bcSAlan Somers     struct fuse_filehandle **fufhp, struct thread *td, const struct ucred *cred,
3547124d2bcSAlan Somers     const struct fuse_open_out *foo)
3555fe58019SAttilio Rao {
3565fe58019SAttilio Rao 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
3575fe58019SAttilio Rao 	struct fuse_filehandle *fufh;
3585fe58019SAttilio Rao 
3591cedd6dfSAlan Somers 	fufh = malloc(sizeof(struct fuse_filehandle), M_FUSE_FILEHANDLE,
3601cedd6dfSAlan Somers 		M_WAITOK);
3611cedd6dfSAlan Somers 	MPASS(fufh != NULL);
3629e444871SAlan Somers 	fufh->fh_id = foo->fh;
3639e444871SAlan Somers 	fufh->fufh_type = fufh_type;
364f8d4af10SAlan Somers 	fufh->gid = cred->cr_rgid;
365f8d4af10SAlan Somers 	fufh->uid = cred->cr_uid;
366a7e81cb3SAlan Somers 	fufh->pid = td->td_proc->p_pid;
3679e444871SAlan Somers 	fufh->fuse_open_flags = foo->open_flags;
3685fe58019SAttilio Rao 	if (!FUFH_IS_VALID(fufh)) {
3695fe58019SAttilio Rao 		panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
3705fe58019SAttilio Rao 	}
3711cedd6dfSAlan Somers 	LIST_INSERT_HEAD(&fvdat->handles, fufh, next);
3725fe58019SAttilio Rao 	if (fufhp != NULL)
3735fe58019SAttilio Rao 		*fufhp = fufh;
3745fe58019SAttilio Rao 
375560a55d0SAlan Somers 	counter_u64_add(fuse_fh_count, 1);
376a7e81cb3SAlan Somers 
377a7e81cb3SAlan Somers 	if (foo->open_flags & FOPEN_DIRECT_IO) {
378a7e81cb3SAlan Somers 		ASSERT_VOP_ELOCKED(vp, __func__);
379a7e81cb3SAlan Somers 		VTOFUD(vp)->flag |= FN_DIRECTIO;
380a7e81cb3SAlan Somers 		fuse_io_invalbuf(vp, td);
381a7e81cb3SAlan Somers 	} else {
382a7e81cb3SAlan Somers 		if ((foo->open_flags & FOPEN_KEEP_CACHE) == 0)
383a7e81cb3SAlan Somers 			fuse_io_invalbuf(vp, td);
384a7e81cb3SAlan Somers 	        VTOFUD(vp)->flag &= ~FN_DIRECTIO;
385a7e81cb3SAlan Somers 	}
386a7e81cb3SAlan Somers 
3875fe58019SAttilio Rao }
388560a55d0SAlan Somers 
389560a55d0SAlan Somers void
390560a55d0SAlan Somers fuse_file_init(void)
391560a55d0SAlan Somers {
392560a55d0SAlan Somers 	fuse_fh_count = counter_u64_alloc(M_WAITOK);
393560a55d0SAlan Somers }
394560a55d0SAlan Somers 
395560a55d0SAlan Somers void
396560a55d0SAlan Somers fuse_file_destroy(void)
397560a55d0SAlan Somers {
398560a55d0SAlan Somers 	counter_u64_free(fuse_fh_count);
399560a55d0SAlan Somers }
400