1241519Sattilio/*
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/10/sys/fs/fuse/fuse_internal.c 332023 2018-04-04 13:16:00Z emaste $");
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>
65241519Sattilio#include <sys/conf.h>
66241519Sattilio#include <sys/uio.h>
67241519Sattilio#include <sys/malloc.h>
68241519Sattilio#include <sys/queue.h>
69241519Sattilio#include <sys/lock.h>
70241519Sattilio#include <sys/mutex.h>
71241519Sattilio#include <sys/sx.h>
72241519Sattilio#include <sys/proc.h>
73241519Sattilio#include <sys/mount.h>
74241519Sattilio#include <sys/vnode.h>
75241519Sattilio#include <sys/namei.h>
76241519Sattilio#include <sys/stat.h>
77241519Sattilio#include <sys/unistd.h>
78241519Sattilio#include <sys/filedesc.h>
79241519Sattilio#include <sys/file.h>
80241519Sattilio#include <sys/fcntl.h>
81241519Sattilio#include <sys/dirent.h>
82241519Sattilio#include <sys/bio.h>
83241519Sattilio#include <sys/buf.h>
84241519Sattilio#include <sys/sysctl.h>
85241519Sattilio#include <sys/priv.h>
86241519Sattilio
87241519Sattilio#include "fuse.h"
88241519Sattilio#include "fuse_file.h"
89241519Sattilio#include "fuse_internal.h"
90241519Sattilio#include "fuse_ipc.h"
91241519Sattilio#include "fuse_node.h"
92241519Sattilio#include "fuse_file.h"
93241519Sattilio#include "fuse_param.h"
94241519Sattilio
95241519Sattilio#define FUSE_DEBUG_MODULE INTERNAL
96241519Sattilio#include "fuse_debug.h"
97241519Sattilio
98241519Sattilio#ifdef ZERO_PAD_INCOMPLETE_BUFS
99241519Sattiliostatic int isbzero(void *buf, size_t len);
100241519Sattilio
101241519Sattilio#endif
102241519Sattilio
103241519Sattilio/* access */
104241519Sattilio
105241519Sattilioint
106241519Sattiliofuse_internal_access(struct vnode *vp,
107241519Sattilio    mode_t mode,
108241519Sattilio    struct fuse_access_param *facp,
109241519Sattilio    struct thread *td,
110241519Sattilio    struct ucred *cred)
111241519Sattilio{
112241519Sattilio	int err = 0;
113241519Sattilio	uint32_t mask = 0;
114241519Sattilio	int dataflags;
115241519Sattilio	int vtype;
116241519Sattilio	struct mount *mp;
117241519Sattilio	struct fuse_dispatcher fdi;
118241519Sattilio	struct fuse_access_in *fai;
119241519Sattilio	struct fuse_data *data;
120241519Sattilio
121241519Sattilio	/* NOT YET DONE */
122241519Sattilio	/*
123241519Sattilio	 * If this vnop gives you trouble, just return 0 here for a lazy
124241519Sattilio	 * kludge.
125241519Sattilio	 */
126241519Sattilio	/* return 0;*/
127241519Sattilio
128241519Sattilio	fuse_trace_printf_func();
129241519Sattilio
130241519Sattilio	mp = vnode_mount(vp);
131241519Sattilio	vtype = vnode_vtype(vp);
132241519Sattilio
133241519Sattilio	data = fuse_get_mpdata(mp);
134241519Sattilio	dataflags = data->dataflags;
135241519Sattilio
136241519Sattilio	if ((mode & VWRITE) && vfs_isrdonly(mp)) {
137241519Sattilio		return EACCES;
138241519Sattilio	}
139241519Sattilio	/* Unless explicitly permitted, deny everyone except the fs owner. */
140241519Sattilio	    if (vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) {
141241519Sattilio		if (!(dataflags & FSESS_DAEMON_CAN_SPY)) {
142241519Sattilio			int denied = fuse_match_cred(data->daemoncred,
143241519Sattilio			    cred);
144241519Sattilio
145241519Sattilio			if (denied) {
146241519Sattilio				return EPERM;
147241519Sattilio			}
148241519Sattilio		}
149241519Sattilio		facp->facc_flags |= FACCESS_NOCHECKSPY;
150241519Sattilio	}
151241519Sattilio	if (!(facp->facc_flags & FACCESS_DO_ACCESS)) {
152241519Sattilio		return 0;
153241519Sattilio	}
154241519Sattilio	if (((vtype == VREG) && (mode & VEXEC))) {
155241519Sattilio#ifdef NEED_MOUNT_ARGUMENT_FOR_THIS
156241519Sattilio		/* Let	 the kernel handle this through open / close heuristics.*/
157241519Sattilio		    return ENOTSUP;
158241519Sattilio#else
159241519Sattilio		    /* 	Let the kernel handle this. */
160241519Sattilio		    return 0;
161241519Sattilio#endif
162241519Sattilio	}
163241519Sattilio	if (!fsess_isimpl(mp, FUSE_ACCESS)) {
164241519Sattilio		/* Let the kernel handle this. */
165241519Sattilio		    return 0;
166241519Sattilio	}
167241519Sattilio	if (dataflags & FSESS_DEFAULT_PERMISSIONS) {
168241519Sattilio		/* Let the kernel handle this. */
169241519Sattilio		    return 0;
170241519Sattilio	}
171241519Sattilio	if ((mode & VADMIN) != 0) {
172241519Sattilio		err = priv_check_cred(cred, PRIV_VFS_ADMIN, 0);
173241519Sattilio		if (err) {
174241519Sattilio			return err;
175241519Sattilio		}
176241519Sattilio	}
177241519Sattilio	if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) {
178241519Sattilio		mask |= W_OK;
179241519Sattilio	}
180241519Sattilio	if ((mode & VREAD) != 0) {
181241519Sattilio		mask |= R_OK;
182241519Sattilio	}
183241519Sattilio	if ((mode & VEXEC) != 0) {
184241519Sattilio		mask |= X_OK;
185241519Sattilio	}
186241519Sattilio	bzero(&fdi, sizeof(fdi));
187241519Sattilio
188241519Sattilio	fdisp_init(&fdi, sizeof(*fai));
189241519Sattilio	fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred);
190241519Sattilio
191241519Sattilio	fai = fdi.indata;
192241519Sattilio	fai->mask = F_OK;
193241519Sattilio	fai->mask |= mask;
194241519Sattilio
195241519Sattilio	err = fdisp_wait_answ(&fdi);
196241519Sattilio	fdisp_destroy(&fdi);
197241519Sattilio
198241519Sattilio	if (err == ENOSYS) {
199241519Sattilio		fsess_set_notimpl(mp, FUSE_ACCESS);
200241519Sattilio		err = 0;
201241519Sattilio	}
202241519Sattilio	return err;
203241519Sattilio}
204241519Sattilio
205241519Sattilio/* fsync */
206241519Sattilio
207241519Sattilioint
208241519Sattiliofuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio)
209241519Sattilio{
210241519Sattilio	fuse_trace_printf_func();
211241519Sattilio
212241519Sattilio	if (tick->tk_aw_ohead.error == ENOSYS) {
213241519Sattilio		fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick));
214241519Sattilio	}
215241519Sattilio	return 0;
216241519Sattilio}
217241519Sattilio
218241519Sattilioint
219241519Sattiliofuse_internal_fsync(struct vnode *vp,
220241519Sattilio    struct thread *td,
221241519Sattilio    struct ucred *cred,
222241519Sattilio    struct fuse_filehandle *fufh)
223241519Sattilio{
224241519Sattilio	int op = FUSE_FSYNC;
225241519Sattilio	struct fuse_fsync_in *ffsi;
226241519Sattilio	struct fuse_dispatcher fdi;
227241519Sattilio
228241519Sattilio	fuse_trace_printf_func();
229241519Sattilio
230241519Sattilio	if (vnode_isdir(vp)) {
231241519Sattilio		op = FUSE_FSYNCDIR;
232241519Sattilio	}
233241519Sattilio	fdisp_init(&fdi, sizeof(*ffsi));
234241519Sattilio	fdisp_make_vp(&fdi, op, vp, td, cred);
235241519Sattilio	ffsi = fdi.indata;
236241519Sattilio	ffsi->fh = fufh->fh_id;
237241519Sattilio
238241519Sattilio	ffsi->fsync_flags = 1;		/* datasync */
239241519Sattilio
240241519Sattilio	fuse_insert_callback(fdi.tick, fuse_internal_fsync_callback);
241241519Sattilio	fuse_insert_message(fdi.tick);
242241519Sattilio
243241519Sattilio	fdisp_destroy(&fdi);
244241519Sattilio
245241519Sattilio	return 0;
246241519Sattilio
247241519Sattilio}
248241519Sattilio
249241519Sattilio/* readdir */
250241519Sattilio
251241519Sattilioint
252241519Sattiliofuse_internal_readdir(struct vnode *vp,
253241519Sattilio    struct uio *uio,
254241519Sattilio    struct fuse_filehandle *fufh,
255241519Sattilio    struct fuse_iov *cookediov)
256241519Sattilio{
257241519Sattilio	int err = 0;
258241519Sattilio	struct fuse_dispatcher fdi;
259241519Sattilio	struct fuse_read_in *fri;
260241519Sattilio
261241519Sattilio	if (uio_resid(uio) == 0) {
262241519Sattilio		return 0;
263241519Sattilio	}
264241519Sattilio	fdisp_init(&fdi, 0);
265241519Sattilio
266241519Sattilio	/*
267241519Sattilio	 * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p
268241519Sattilio	 * I/O).
269241519Sattilio	 */
270241519Sattilio
271241519Sattilio	while (uio_resid(uio) > 0) {
272241519Sattilio
273241519Sattilio		fdi.iosize = sizeof(*fri);
274241519Sattilio		fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL);
275241519Sattilio
276241519Sattilio		fri = fdi.indata;
277241519Sattilio		fri->fh = fufh->fh_id;
278241519Sattilio		fri->offset = uio_offset(uio);
279241519Sattilio		fri->size = min(uio_resid(uio), FUSE_DEFAULT_IOSIZE);
280241519Sattilio		/* mp->max_read */
281241519Sattilio
282241519Sattilio		    if ((err = fdisp_wait_answ(&fdi))) {
283241519Sattilio			break;
284241519Sattilio		}
285241519Sattilio		if ((err = fuse_internal_readdir_processdata(uio, fri->size, fdi.answ,
286241519Sattilio		    fdi.iosize, cookediov))) {
287241519Sattilio			break;
288241519Sattilio		}
289241519Sattilio	}
290241519Sattilio
291241519Sattilio	fdisp_destroy(&fdi);
292241519Sattilio	return ((err == -1) ? 0 : err);
293241519Sattilio}
294241519Sattilio
295241519Sattilioint
296241519Sattiliofuse_internal_readdir_processdata(struct uio *uio,
297241519Sattilio    size_t reqsize,
298241519Sattilio    void *buf,
299241519Sattilio    size_t bufsize,
300241519Sattilio    void *param)
301241519Sattilio{
302241519Sattilio	int err = 0;
303241519Sattilio	int cou = 0;
304241519Sattilio	int bytesavail;
305241519Sattilio	size_t freclen;
306241519Sattilio
307241519Sattilio	struct dirent *de;
308241519Sattilio	struct fuse_dirent *fudge;
309241519Sattilio	struct fuse_iov *cookediov = param;
310241519Sattilio
311241519Sattilio	if (bufsize < FUSE_NAME_OFFSET) {
312241519Sattilio		return -1;
313241519Sattilio	}
314241519Sattilio	for (;;) {
315241519Sattilio
316241519Sattilio		if (bufsize < FUSE_NAME_OFFSET) {
317241519Sattilio			err = -1;
318241519Sattilio			break;
319241519Sattilio		}
320241519Sattilio		fudge = (struct fuse_dirent *)buf;
321241519Sattilio		freclen = FUSE_DIRENT_SIZE(fudge);
322241519Sattilio
323241519Sattilio		cou++;
324241519Sattilio
325241519Sattilio		if (bufsize < freclen) {
326241519Sattilio			err = ((cou == 1) ? -1 : 0);
327241519Sattilio			break;
328241519Sattilio		}
329241519Sattilio#ifdef ZERO_PAD_INCOMPLETE_BUFS
330241519Sattilio		if (isbzero(buf, FUSE_NAME_OFFSET)) {
331241519Sattilio			err = -1;
332241519Sattilio			break;
333241519Sattilio		}
334241519Sattilio#endif
335241519Sattilio
336241519Sattilio		if (!fudge->namelen || fudge->namelen > MAXNAMLEN) {
337241519Sattilio			err = EINVAL;
338241519Sattilio			break;
339241519Sattilio		}
340241519Sattilio		bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)
341241519Sattilio					    &fudge->namelen);
342241519Sattilio
343241519Sattilio		if (bytesavail > uio_resid(uio)) {
344241519Sattilio			err = -1;
345241519Sattilio			break;
346241519Sattilio		}
347241519Sattilio		fiov_refresh(cookediov);
348241519Sattilio		fiov_adjust(cookediov, bytesavail);
349241519Sattilio
350241519Sattilio		de = (struct dirent *)cookediov->base;
351241519Sattilio		de->d_fileno = fudge->ino;	/* XXX: truncation */
352241519Sattilio		de->d_reclen = bytesavail;
353241519Sattilio		de->d_type = fudge->type;
354241519Sattilio		de->d_namlen = fudge->namelen;
355241519Sattilio		memcpy((char *)cookediov->base + sizeof(struct dirent) -
356241519Sattilio		       MAXNAMLEN - 1,
357241519Sattilio		       (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
358332023Semaste		((char *)cookediov->base)[bytesavail - 1] = '\0';
359241519Sattilio
360241519Sattilio		err = uiomove(cookediov->base, cookediov->len, uio);
361241519Sattilio		if (err) {
362241519Sattilio			break;
363241519Sattilio		}
364241519Sattilio		buf = (char *)buf + freclen;
365241519Sattilio		bufsize -= freclen;
366241519Sattilio		uio_setoffset(uio, fudge->off);
367241519Sattilio	}
368241519Sattilio
369241519Sattilio	return err;
370241519Sattilio}
371241519Sattilio
372241519Sattilio/* remove */
373241519Sattilio
374241519Sattilio#define INVALIDATE_CACHED_VATTRS_UPON_UNLINK 1
375241519Sattilioint
376241519Sattiliofuse_internal_remove(struct vnode *dvp,
377241519Sattilio    struct vnode *vp,
378241519Sattilio    struct componentname *cnp,
379241519Sattilio    enum fuse_opcode op)
380241519Sattilio{
381241519Sattilio	struct fuse_dispatcher fdi;
382241519Sattilio
383241519Sattilio	struct vattr *vap = VTOVA(vp);
384241519Sattilio
385241519Sattilio#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK
386241519Sattilio	int need_invalidate = 0;
387241519Sattilio	uint64_t target_nlink = 0;
388241519Sattilio
389241519Sattilio#endif
390241519Sattilio	int err = 0;
391241519Sattilio
392241519Sattilio	debug_printf("dvp=%p, cnp=%p, op=%d\n", vp, cnp, op);
393241519Sattilio
394241519Sattilio	fdisp_init(&fdi, cnp->cn_namelen + 1);
395241519Sattilio	fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred);
396241519Sattilio
397241519Sattilio	memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
398241519Sattilio	((char *)fdi.indata)[cnp->cn_namelen] = '\0';
399241519Sattilio
400241519Sattilio#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK
401241519Sattilio	if (vap->va_nlink > 1) {
402241519Sattilio		need_invalidate = 1;
403241519Sattilio		target_nlink = vap->va_nlink;
404241519Sattilio	}
405241519Sattilio#endif
406241519Sattilio
407241519Sattilio	err = fdisp_wait_answ(&fdi);
408241519Sattilio	fdisp_destroy(&fdi);
409241519Sattilio	return err;
410241519Sattilio}
411241519Sattilio
412241519Sattilio/* rename */
413241519Sattilio
414241519Sattilioint
415241519Sattiliofuse_internal_rename(struct vnode *fdvp,
416241519Sattilio    struct componentname *fcnp,
417241519Sattilio    struct vnode *tdvp,
418241519Sattilio    struct componentname *tcnp)
419241519Sattilio{
420241519Sattilio	struct fuse_dispatcher fdi;
421241519Sattilio	struct fuse_rename_in *fri;
422241519Sattilio	int err = 0;
423241519Sattilio
424241519Sattilio	fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
425241519Sattilio	fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred);
426241519Sattilio
427241519Sattilio	fri = fdi.indata;
428241519Sattilio	fri->newdir = VTOI(tdvp);
429241519Sattilio	memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
430241519Sattilio	    fcnp->cn_namelen);
431241519Sattilio	((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
432241519Sattilio	memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
433241519Sattilio	    tcnp->cn_nameptr, tcnp->cn_namelen);
434241519Sattilio	((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
435241519Sattilio	    tcnp->cn_namelen + 1] = '\0';
436241519Sattilio
437241519Sattilio	err = fdisp_wait_answ(&fdi);
438241519Sattilio	fdisp_destroy(&fdi);
439241519Sattilio	return err;
440241519Sattilio}
441241519Sattilio
442241519Sattilio/* strategy */
443241519Sattilio
444241519Sattilio/* entity creation */
445241519Sattilio
446241519Sattiliovoid
447241519Sattiliofuse_internal_newentry_makerequest(struct mount *mp,
448241519Sattilio    uint64_t dnid,
449241519Sattilio    struct componentname *cnp,
450241519Sattilio    enum fuse_opcode op,
451241519Sattilio    void *buf,
452241519Sattilio    size_t bufsize,
453241519Sattilio    struct fuse_dispatcher *fdip)
454241519Sattilio{
455241519Sattilio	debug_printf("fdip=%p\n", fdip);
456241519Sattilio
457241519Sattilio	fdip->iosize = bufsize + cnp->cn_namelen + 1;
458241519Sattilio
459241519Sattilio	fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred);
460241519Sattilio	memcpy(fdip->indata, buf, bufsize);
461241519Sattilio	memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
462241519Sattilio	((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
463241519Sattilio}
464241519Sattilio
465241519Sattilioint
466241519Sattiliofuse_internal_newentry_core(struct vnode *dvp,
467241519Sattilio    struct vnode **vpp,
468241519Sattilio    struct componentname *cnp,
469241519Sattilio    enum vtype vtyp,
470241519Sattilio    struct fuse_dispatcher *fdip)
471241519Sattilio{
472241519Sattilio	int err = 0;
473241519Sattilio	struct fuse_entry_out *feo;
474241519Sattilio	struct mount *mp = vnode_mount(dvp);
475241519Sattilio
476241519Sattilio	if ((err = fdisp_wait_answ(fdip))) {
477241519Sattilio		return err;
478241519Sattilio	}
479241519Sattilio	feo = fdip->answ;
480241519Sattilio
481241519Sattilio	if ((err = fuse_internal_checkentry(feo, vtyp))) {
482241519Sattilio		return err;
483241519Sattilio	}
484241519Sattilio	err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, vtyp);
485241519Sattilio	if (err) {
486241519Sattilio		fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred,
487241519Sattilio		    feo->nodeid, 1);
488241519Sattilio		return err;
489241519Sattilio	}
490241519Sattilio	cache_attrs(*vpp, feo);
491241519Sattilio
492241519Sattilio	return err;
493241519Sattilio}
494241519Sattilio
495241519Sattilioint
496241519Sattiliofuse_internal_newentry(struct vnode *dvp,
497241519Sattilio    struct vnode **vpp,
498241519Sattilio    struct componentname *cnp,
499241519Sattilio    enum fuse_opcode op,
500241519Sattilio    void *buf,
501241519Sattilio    size_t bufsize,
502241519Sattilio    enum vtype vtype)
503241519Sattilio{
504241519Sattilio	int err;
505241519Sattilio	struct fuse_dispatcher fdi;
506241519Sattilio	struct mount *mp = vnode_mount(dvp);
507241519Sattilio
508241519Sattilio	fdisp_init(&fdi, 0);
509241519Sattilio	fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
510241519Sattilio	    bufsize, &fdi);
511241519Sattilio	err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi);
512241519Sattilio	fdisp_destroy(&fdi);
513241519Sattilio
514241519Sattilio	return err;
515241519Sattilio}
516241519Sattilio
517241519Sattilio/* entity destruction */
518241519Sattilio
519241519Sattilioint
520241519Sattiliofuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio)
521241519Sattilio{
522241519Sattilio	fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL,
523241519Sattilio	    ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1);
524241519Sattilio
525241519Sattilio	return 0;
526241519Sattilio}
527241519Sattilio
528241519Sattiliovoid
529241519Sattiliofuse_internal_forget_send(struct mount *mp,
530241519Sattilio    struct thread *td,
531241519Sattilio    struct ucred *cred,
532241519Sattilio    uint64_t nodeid,
533241519Sattilio    uint64_t nlookup)
534241519Sattilio{
535241519Sattilio
536241519Sattilio	struct fuse_dispatcher fdi;
537241519Sattilio	struct fuse_forget_in *ffi;
538241519Sattilio
539241519Sattilio	debug_printf("mp=%p, nodeid=%ju, nlookup=%ju\n",
540241519Sattilio	    mp, (uintmax_t)nodeid, (uintmax_t)nlookup);
541241519Sattilio
542241519Sattilio	/*
543241519Sattilio         * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
544241519Sattilio         *         (long long unsigned) nodeid));
545241519Sattilio         */
546241519Sattilio
547241519Sattilio	fdisp_init(&fdi, sizeof(*ffi));
548241519Sattilio	fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred);
549241519Sattilio
550241519Sattilio	ffi = fdi.indata;
551241519Sattilio	ffi->nlookup = nlookup;
552241519Sattilio
553241519Sattilio	fuse_insert_message(fdi.tick);
554241519Sattilio	fdisp_destroy(&fdi);
555241519Sattilio}
556241519Sattilio
557241519Sattiliovoid
558241519Sattiliofuse_internal_vnode_disappear(struct vnode *vp)
559241519Sattilio{
560241519Sattilio	struct fuse_vnode_data *fvdat = VTOFUD(vp);
561241519Sattilio
562241519Sattilio	ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear");
563241519Sattilio	fvdat->flag |= FN_REVOKED;
564241519Sattilio	cache_purge(vp);
565241519Sattilio}
566241519Sattilio
567241519Sattilio/* fuse start/stop */
568241519Sattilio
569241519Sattilioint
570241519Sattiliofuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
571241519Sattilio{
572241519Sattilio	int err = 0;
573241519Sattilio	struct fuse_data *data = tick->tk_data;
574241519Sattilio	struct fuse_init_out *fiio;
575241519Sattilio
576241519Sattilio	if ((err = tick->tk_aw_ohead.error)) {
577241519Sattilio		goto out;
578241519Sattilio	}
579241519Sattilio	if ((err = fticket_pull(tick, uio))) {
580241519Sattilio		goto out;
581241519Sattilio	}
582241519Sattilio	fiio = fticket_resp(tick)->base;
583241519Sattilio
584241519Sattilio	/* XXX: Do we want to check anything further besides this? */
585241519Sattilio	if (fiio->major < 7) {
586241519Sattilio		debug_printf("userpace version too low\n");
587241519Sattilio		err = EPROTONOSUPPORT;
588241519Sattilio		goto out;
589241519Sattilio	}
590241519Sattilio	data->fuse_libabi_major = fiio->major;
591241519Sattilio	data->fuse_libabi_minor = fiio->minor;
592241519Sattilio
593241519Sattilio	if (fuse_libabi_geq(data, 7, 5)) {
594241519Sattilio		if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) {
595241519Sattilio			data->max_write = fiio->max_write;
596241519Sattilio		} else {
597241519Sattilio			err = EINVAL;
598241519Sattilio		}
599241519Sattilio	} else {
600241519Sattilio		/* Old fix values */
601241519Sattilio		data->max_write = 4096;
602241519Sattilio	}
603241519Sattilio
604241519Sattilioout:
605241519Sattilio	if (err) {
606241519Sattilio		fdata_set_dead(data);
607241519Sattilio	}
608241519Sattilio	FUSE_LOCK();
609241519Sattilio	data->dataflags |= FSESS_INITED;
610241519Sattilio	wakeup(&data->ticketer);
611241519Sattilio	FUSE_UNLOCK();
612241519Sattilio
613241519Sattilio	return 0;
614241519Sattilio}
615241519Sattilio
616241519Sattiliovoid
617241519Sattiliofuse_internal_send_init(struct fuse_data *data, struct thread *td)
618241519Sattilio{
619241519Sattilio	struct fuse_init_in *fiii;
620241519Sattilio	struct fuse_dispatcher fdi;
621241519Sattilio
622241519Sattilio	fdisp_init(&fdi, sizeof(*fiii));
623241519Sattilio	fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL);
624241519Sattilio	fiii = fdi.indata;
625241519Sattilio	fiii->major = FUSE_KERNEL_VERSION;
626241519Sattilio	fiii->minor = FUSE_KERNEL_MINOR_VERSION;
627241519Sattilio	fiii->max_readahead = FUSE_DEFAULT_IOSIZE * 16;
628241519Sattilio	fiii->flags = 0;
629241519Sattilio
630241519Sattilio	fuse_insert_callback(fdi.tick, fuse_internal_init_callback);
631241519Sattilio	fuse_insert_message(fdi.tick);
632241519Sattilio	fdisp_destroy(&fdi);
633241519Sattilio}
634241519Sattilio
635241519Sattilio#ifdef ZERO_PAD_INCOMPLETE_BUFS
636241519Sattiliostatic int
637241519Sattilioisbzero(void *buf, size_t len)
638241519Sattilio{
639241519Sattilio	int i;
640241519Sattilio
641241519Sattilio	for (i = 0; i < len; i++) {
642241519Sattilio		if (((char *)buf)[i])
643241519Sattilio			return (0);
644241519Sattilio	}
645241519Sattilio
646241519Sattilio	return (1);
647241519Sattilio}
648241519Sattilio
649241519Sattilio#endif
650