fuse_internal.c revision 241519
1339631Sphilip/*
2339631Sphilip * Copyright (c) 2007-2009 Google Inc. and Amit Singh
3192886Sedwin * All rights reserved.
4192886Sedwin *
564499Swollman * Redistribution and use in source and binary forms, with or without
6273719Sedwin * modification, are permitted provided that the following conditions are
72742Swollman * met:
8273719Sedwin *
9273719Sedwin * * Redistributions of source code must retain the above copyright
102742Swollman *   notice, this list of conditions and the following disclaimer.
11316350Sbapt * * Redistributions in binary form must reproduce the above
12274563Sedwin *   copyright notice, this list of conditions and the following disclaimer
13274563Sedwin *   in the documentation and/or other materials provided with the
14158421Swollman *   distribution.
15158421Swollman * * Neither the name of Google Inc. nor the names of its
16274563Sedwin *   contributors may be used to endorse or promote products derived from
172742Swollman *   this software without specific prior written permission.
18316350Sbapt *
19316350Sbapt * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2020094Swollman * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2120094Swollman * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22274563Sedwin * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23274563Sedwin * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2420094Swollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25274563Sedwin * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26274563Sedwin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27325160Sphilip * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2820094Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29316350Sbapt * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30328476Sphilip *
31316350Sbapt * Copyright (C) 2005 Csaba Henk.
32316350Sbapt * All rights reserved.
332742Swollman *
342742Swollman * Redistribution and use in source and binary forms, with or without
352742Swollman * modification, are permitted provided that the following conditions
362742Swollman * are met:
372742Swollman * 1. Redistributions of source code must retain the above copyright
382742Swollman *    notice, this list of conditions and the following disclaimer.
392742Swollman * 2. Redistributions in binary form must reproduce the above copyright
4019878Swollman *    notice, this list of conditions and the following disclaimer in the
412742Swollman *    documentation and/or other materials provided with the distribution.
422742Swollman *
432742Swollman * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44270817Spluknet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
452742Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
462742Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
47149514Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4821217Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
499908Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
509908Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
512742Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52331663Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5319878Swollman * SUCH DAMAGE.
54331663Sphilip */
5519878Swollman
56331663Sphilip#include <sys/cdefs.h>
57331663Sphilip__FBSDID("$FreeBSD: head/sys/fs/fuse/fuse_internal.c 241519 2012-10-13 23:54:26Z attilio $");
5819878Swollman
59331663Sphilip#include <sys/types.h>
6019878Swollman#include <sys/module.h>
61331663Sphilip#include <sys/systm.h>
6219878Swollman#include <sys/errno.h>
63331663Sphilip#include <sys/param.h>
6419878Swollman#include <sys/kernel.h>
65331663Sphilip#include <sys/conf.h>
6619878Swollman#include <sys/uio.h>
67331663Sphilip#include <sys/malloc.h>
6893799Swollman#include <sys/queue.h>
69331663Sphilip#include <sys/lock.h>
7058787Sru#include <sys/mutex.h>
71331663Sphilip#include <sys/sx.h>
7219878Swollman#include <sys/proc.h>
73331663Sphilip#include <sys/mount.h>
749908Swollman#include <sys/vnode.h>
75149514Swollman#include <sys/namei.h>
769908Swollman#include <sys/stat.h>
779908Swollman#include <sys/unistd.h>
78270817Spluknet#include <sys/filedesc.h>
7921217Swollman#include <sys/file.h>
8019878Swollman#include <sys/fcntl.h>
81331663Sphilip#include <sys/dirent.h>
829908Swollman#include <sys/bio.h>
83149514Swollman#include <sys/buf.h>
849908Swollman#include <sys/sysctl.h>
859908Swollman#include <sys/priv.h>
869908Swollman
879908Swollman#include "fuse.h"
8858787Sru#include "fuse_file.h"
8958787Sru#include "fuse_internal.h"
9058787Sru#include "fuse_ipc.h"
9164499Swollman#include "fuse_node.h"
92331663Sphilip#include "fuse_file.h"
93175034Sedwin#include "fuse_param.h"
94175034Sedwin
95175034Sedwin#define FUSE_DEBUG_MODULE INTERNAL
96175034Sedwin#include "fuse_debug.h"
97175034Sedwin
9858787Sru#ifdef ZERO_PAD_INCOMPLETE_BUFS
9958787Srustatic int isbzero(void *buf, size_t len);
100270817Spluknet
10158787Sru#endif
10258787Sru
10358787Sru/* access */
104270817Spluknet
10564499Swollmanint
106270817Spluknetfuse_internal_access(struct vnode *vp,
10764499Swollman    mode_t mode,
10864499Swollman    struct fuse_access_param *facp,
10986222Swollman    struct thread *td,
11086222Swollman    struct ucred *cred)
11186222Swollman{
11286222Swollman	int err = 0;
11386222Swollman	uint32_t mask = 0;
114286751Sedwin	int dataflags;
11586222Swollman	int vtype;
11686222Swollman	struct mount *mp;
11786222Swollman	struct fuse_dispatcher fdi;
11886222Swollman	struct fuse_access_in *fai;
11986222Swollman	struct fuse_data *data;
12086222Swollman
12186222Swollman	/* NOT YET DONE */
12286222Swollman	/*
12386222Swollman	 * If this vnop gives you trouble, just return 0 here for a lazy
12486222Swollman	 * kludge.
12586222Swollman	 */
12686222Swollman	/* return 0;*/
12786222Swollman
12886222Swollman	fuse_trace_printf_func();
12986222Swollman
13086222Swollman	mp = vnode_mount(vp);
13186222Swollman	vtype = vnode_vtype(vp);
132175034Sedwin
133175034Sedwin	data = fuse_get_mpdata(mp);
134175034Sedwin	dataflags = data->dataflags;
135175034Sedwin
136175034Sedwin	if ((mode & VWRITE) && vfs_isrdonly(mp)) {
137175034Sedwin		return EACCES;
138175034Sedwin	}
139270817Spluknet	/* Unless explicitly permitted, deny everyone except the fs owner. */
140175034Sedwin	    if (vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) {
141270817Spluknet		if (!(dataflags & FSESS_DAEMON_CAN_SPY)) {
142175034Sedwin			int denied = fuse_match_cred(data->daemoncred,
143175034Sedwin			    cred);
144175034Sedwin
145175034Sedwin			if (denied) {
146175034Sedwin				return EPERM;
147175034Sedwin			}
148175034Sedwin		}
149175034Sedwin		facp->facc_flags |= FACCESS_NOCHECKSPY;
150183066Sedwin	}
151183066Sedwin	if (!(facp->facc_flags & FACCESS_DO_ACCESS)) {
152183066Sedwin		return 0;
153183066Sedwin	}
154183066Sedwin	if (((vtype == VREG) && (mode & VEXEC))) {
155183066Sedwin#ifdef NEED_MOUNT_ARGUMENT_FOR_THIS
156183066Sedwin		/* Let	 the kernel handle this through open / close heuristics.*/
157183066Sedwin		    return ENOTSUP;
158286751Sedwin#else
159286751Sedwin		    /* 	Let the kernel handle this. */
160286751Sedwin		    return 0;
161183864Sedwin#endif
162286751Sedwin	}
163183864Sedwin	if (!fsess_isimpl(mp, FUSE_ACCESS)) {
164183864Sedwin		/* Let the kernel handle this. */
165183864Sedwin		    return 0;
166184406Sedwin	}
167273719Sedwin	if (dataflags & FSESS_DEFAULT_PERMISSIONS) {
168273719Sedwin		/* Let the kernel handle this. */
169184406Sedwin		    return 0;
170184406Sedwin	}
171270817Spluknet	if ((mode & VADMIN) != 0) {
172270817Spluknet		err = priv_check_cred(cred, PRIV_VFS_ADMIN, 0);
173270817Spluknet		if (err) {
174270817Spluknet			return err;
175184406Sedwin		}
176184406Sedwin	}
177273719Sedwin	if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) {
178273719Sedwin		mask |= W_OK;
179273719Sedwin	}
180184406Sedwin	if ((mode & VREAD) != 0) {
181184406Sedwin		mask |= R_OK;
182198515Sedwin	}
183198515Sedwin	if ((mode & VEXEC) != 0) {
184198515Sedwin		mask |= X_OK;
185273719Sedwin	}
186273719Sedwin	bzero(&fdi, sizeof(fdi));
187198515Sedwin
188270817Spluknet	fdisp_init(&fdi, sizeof(*fai));
189270817Spluknet	fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred);
190270817Spluknet
191270817Spluknet	fai = fdi.indata;
192270817Spluknet	fai->mask = F_OK;
193270817Spluknet	fai->mask |= mask;
194198515Sedwin
195331663Sphilip	err = fdisp_wait_answ(&fdi);
196198515Sedwin	fdisp_destroy(&fdi);
197331663Sphilip
198240457Sedwin	if (err == ENOSYS) {
199136638Swollman		fsess_set_notimpl(mp, FUSE_ACCESS);
200136638Swollman		err = 0;
201136638Swollman	}
202136638Swollman	return err;
203136638Swollman}
204136638Swollman
205136638Swollman/* fsync */
20693799Swollman
207331663Sphilipint
208273719Sedwinfuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio)
209273719Sedwin{
210270817Spluknet	fuse_trace_printf_func();
21193799Swollman
212331663Sphilip	if (tick->tk_aw_ohead.error == ENOSYS) {
213331663Sphilip		fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick));
214331663Sphilip	}
215136638Swollman	return 0;
216136638Swollman}
217136638Swollman
218136638Swollmanint
219136638Swollmanfuse_internal_fsync(struct vnode *vp,
220136638Swollman    struct thread *td,
221136638Swollman    struct ucred *cred,
222136638Swollman    struct fuse_filehandle *fufh)
223136638Swollman{
224136638Swollman	int op = FUSE_FSYNC;
225136638Swollman	struct fuse_fsync_in *ffsi;
226136638Swollman	struct fuse_dispatcher fdi;
227270817Spluknet
228136638Swollman	fuse_trace_printf_func();
229136638Swollman
230270817Spluknet	if (vnode_isdir(vp)) {
231136638Swollman		op = FUSE_FSYNCDIR;
232136638Swollman	}
233136638Swollman	fdisp_init(&fdi, sizeof(*ffsi));
234136638Swollman	fdisp_make_vp(&fdi, op, vp, td, cred);
235136638Swollman	ffsi = fdi.indata;
236136638Swollman	ffsi->fh = fufh->fh_id;
237136638Swollman
238136638Swollman	ffsi->fsync_flags = 1;		/* datasync */
239136638Swollman
240136638Swollman	fuse_insert_callback(fdi.tick, fuse_internal_fsync_callback);
241136638Swollman	fuse_insert_message(fdi.tick);
242136638Swollman
243136638Swollman	fdisp_destroy(&fdi);
244136638Swollman
245136638Swollman	return 0;
246136638Swollman
247136638Swollman}
248136638Swollman
249136638Swollman/* readdir */
250136638Swollman
251136638Swollmanint
252136638Swollmanfuse_internal_readdir(struct vnode *vp,
253136638Swollman    struct uio *uio,
254136638Swollman    struct fuse_filehandle *fufh,
255136638Swollman    struct fuse_iov *cookediov)
256136638Swollman{
257136638Swollman	int err = 0;
258136638Swollman	struct fuse_dispatcher fdi;
259136638Swollman	struct fuse_read_in *fri;
26093799Swollman
261177591Sedwin	if (uio_resid(uio) == 0) {
262177591Sedwin		return 0;
263177591Sedwin	}
264177591Sedwin	fdisp_init(&fdi, 0);
265270817Spluknet
266177591Sedwin	/*
267177591Sedwin	 * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p
268177591Sedwin	 * I/O).
269177591Sedwin	 */
270177591Sedwin
271177591Sedwin	while (uio_resid(uio) > 0) {
272325160Sphilip
273325160Sphilip		fdi.iosize = sizeof(*fri);
274177591Sedwin		fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL);
275270817Spluknet
276177591Sedwin		fri = fdi.indata;
277177591Sedwin		fri->fh = fufh->fh_id;
278177591Sedwin		fri->offset = uio_offset(uio);
279177591Sedwin		fri->size = min(uio_resid(uio), FUSE_DEFAULT_IOSIZE);
280177591Sedwin		/* mp->max_read */
281240457Sedwin
282240457Sedwin		    if ((err = fdisp_wait_answ(&fdi))) {
283240457Sedwin			break;
284273719Sedwin		}
285177591Sedwin		if ((err = fuse_internal_readdir_processdata(uio, fri->size, fdi.answ,
286177591Sedwin		    fdi.iosize, cookediov))) {
287177591Sedwin			break;
288177591Sedwin		}
289177591Sedwin	}
290270817Spluknet
291177591Sedwin	fdisp_destroy(&fdi);
292177591Sedwin	return ((err == -1) ? 0 : err);
293177591Sedwin}
294177591Sedwin
295177591Sedwinint
296177591Sedwinfuse_internal_readdir_processdata(struct uio *uio,
297177591Sedwin    size_t reqsize,
298177591Sedwin    void *buf,
299177591Sedwin    size_t bufsize,
300177591Sedwin    void *param)
301177591Sedwin{
302177591Sedwin	int err = 0;
303177591Sedwin	int cou = 0;
304177591Sedwin	int bytesavail;
305177591Sedwin	size_t freclen;
306177591Sedwin
307177591Sedwin	struct dirent *de;
308177591Sedwin	struct fuse_dirent *fudge;
309177591Sedwin	struct fuse_iov *cookediov = param;
310177591Sedwin
311177591Sedwin	if (bufsize < FUSE_NAME_OFFSET) {
312177591Sedwin		return -1;
313177591Sedwin	}
314177591Sedwin	for (;;) {
315177591Sedwin
316273719Sedwin		if (bufsize < FUSE_NAME_OFFSET) {
317273719Sedwin			err = -1;
318273719Sedwin			break;
319181421Sedwin		}
320181421Sedwin		fudge = (struct fuse_dirent *)buf;
321181421Sedwin		freclen = FUSE_DIRENT_SIZE(fudge);
322181421Sedwin
323181421Sedwin		cou++;
324190372Sedwin
325190372Sedwin		if (bufsize < freclen) {
326190372Sedwin			err = ((cou == 1) ? -1 : 0);
327190372Sedwin			break;
32893799Swollman		}
329190372Sedwin#ifdef ZERO_PAD_INCOMPLETE_BUFS
330190372Sedwin		if (isbzero(buf, FUSE_NAME_OFFSET)) {
331270817Spluknet			err = -1;
332270817Spluknet			break;
333190372Sedwin		}
334248307Sedwin#endif
335190372Sedwin
336240457Sedwin		if (!fudge->namelen || fudge->namelen > MAXNAMLEN) {
337248307Sedwin			err = EINVAL;
338248307Sedwin			break;
339190372Sedwin		}
340190372Sedwin		bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)
341190372Sedwin					    &fudge->namelen);
342190372Sedwin
343190372Sedwin		if (bytesavail > uio_resid(uio)) {
344190372Sedwin			err = -1;
345198515Sedwin			break;
346198515Sedwin		}
347190372Sedwin		fiov_refresh(cookediov);
348198515Sedwin		fiov_adjust(cookediov, bytesavail);
349198515Sedwin
350198515Sedwin		de = (struct dirent *)cookediov->base;
351198515Sedwin		de->d_fileno = fudge->ino;	/* XXX: truncation */
352198515Sedwin		de->d_reclen = bytesavail;
353198515Sedwin		de->d_type = fudge->type;
354197597Sedwin		de->d_namlen = fudge->namelen;
355198515Sedwin		memcpy((char *)cookediov->base + sizeof(struct dirent) -
356197597Sedwin		       MAXNAMLEN - 1,
357198515Sedwin		       (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
358198515Sedwin		((char *)cookediov->base)[bytesavail] = '\0';
359198515Sedwin
360198515Sedwin		err = uiomove(cookediov->base, cookediov->len, uio);
361198515Sedwin		if (err) {
362198515Sedwin			break;
363198515Sedwin		}
364198515Sedwin		buf = (char *)buf + freclen;
365198515Sedwin		bufsize -= freclen;
366198515Sedwin		uio_setoffset(uio, fudge->off);
367198515Sedwin	}
368198515Sedwin
369198515Sedwin	return err;
370197597Sedwin}
371206868Sedwin
372273719Sedwin/* remove */
373206868Sedwin
374270817Spluknet#ifdef XXXIP
375206868Sedwinstatic int
376206868Sedwinfuse_internal_remove_callback(struct vnode *vp, void *cargs)
377270817Spluknet{
378206868Sedwin	struct vattr *vap;
379206868Sedwin	uint64_t target_nlink;
380206868Sedwin
381206868Sedwin	vap = VTOVA(vp);
382206868Sedwin
383206868Sedwin	target_nlink = *(uint64_t *)cargs;
384206868Sedwin
385206868Sedwin	/* somewhat lame "heuristics", but you got better ideas? */
386206868Sedwin	if ((vap->va_nlink == target_nlink) && vnode_isreg(vp)) {
387206868Sedwin		fuse_invalidate_attr(vp);
388331663Sphilip	}
389307362Sbapt	return 0;
390331663Sphilip}
391307362Sbapt
392325160Sphilip#endif
393257697Sedwin
394257697Sedwin#define INVALIDATE_CACHED_VATTRS_UPON_UNLINK 1
395257697Sedwinint
396257697Sedwinfuse_internal_remove(struct vnode *dvp,
397339631Sphilip    struct vnode *vp,
398257697Sedwin    struct componentname *cnp,
3992742Swollman    enum fuse_opcode op)
40020094Swollman{
401136638Swollman	struct fuse_dispatcher fdi;
402273719Sedwin
403273719Sedwin	struct vattr *vap = VTOVA(vp);
404316350Sbapt
405316350Sbapt#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK
406316350Sbapt	int need_invalidate = 0;
407316350Sbapt	uint64_t target_nlink = 0;
408316350Sbapt
40920094Swollman#endif
410270817Spluknet	int err = 0;
411184406Sedwin
41220094Swollman	debug_printf("dvp=%p, cnp=%p, op=%d\n", vp, cnp, op);
413158421Swollman
41493799Swollman	fdisp_init(&fdi, cnp->cn_namelen + 1);
41593799Swollman	fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred);
41693799Swollman
41793799Swollman	memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
41893799Swollman	((char *)fdi.indata)[cnp->cn_namelen] = '\0';
41993799Swollman
420136638Swollman#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK
42193799Swollman	if (vap->va_nlink > 1) {
422316350Sbapt		need_invalidate = 1;
423316350Sbapt		target_nlink = vap->va_nlink;
424316350Sbapt	}
425316350Sbapt#endif
426316350Sbapt
427316350Sbapt	err = fdisp_wait_answ(&fdi);
428316350Sbapt	fdisp_destroy(&fdi);
42920094Swollman
430270817Spluknet	fuse_invalidate_attr(dvp);
431184406Sedwin	fuse_invalidate_attr(vp);
432184406Sedwin
433316350Sbapt#ifdef XXXIP
434316350Sbapt	/*
435316350Sbapt         * XXX: INVALIDATE_CACHED_VATTRS_UPON_UNLINK
436316350Sbapt         *
437316350Sbapt         * Consider the case where vap->va_nlink > 1 for the entity being
438316350Sbapt         * removed. In our world, other in-memory vnodes that share a link
439316350Sbapt         * count each with this one may not know right way that this one just
440316350Sbapt         * got deleted. We should let them know, say, through a vnode_iterate()
441184406Sedwin         * here and a callback that does fuse_invalidate_attr(vp) on each
442270817Spluknet         * relevant vnode.
443136638Swollman         */
444136638Swollman	if (need_invalidate && !err) {
445316350Sbapt		vnode_iterate(vnode_mount(vp), 0, fuse_internal_remove_callback,
446316350Sbapt		    (void *)&target_nlink);
447316350Sbapt	}
448316350Sbapt#endif
449316350Sbapt
450316350Sbapt	return err;
451316350Sbapt}
452316350Sbapt
453316350Sbapt/* rename */
454136638Swollman
455136638Swollmanint
456136638Swollmanfuse_internal_rename(struct vnode *fdvp,
457136638Swollman    struct componentname *fcnp,
458316350Sbapt    struct vnode *tdvp,
459316350Sbapt    struct componentname *tcnp)
460316350Sbapt{
461316350Sbapt	struct fuse_dispatcher fdi;
462316350Sbapt	struct fuse_rename_in *fri;
463316350Sbapt	int err = 0;
464316350Sbapt
465316350Sbapt	fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
466316350Sbapt	fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred);
467316350Sbapt
468136638Swollman	fri = fdi.indata;
469136638Swollman	fri->newdir = VTOI(tdvp);
470136638Swollman	memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
471136638Swollman	    fcnp->cn_namelen);
472316350Sbapt	((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
473316350Sbapt	memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
474316350Sbapt	    tcnp->cn_nameptr, tcnp->cn_namelen);
475316350Sbapt	((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
476316350Sbapt	    tcnp->cn_namelen + 1] = '\0';
477316350Sbapt
478316350Sbapt	err = fdisp_wait_answ(&fdi);
479316350Sbapt	fdisp_destroy(&fdi);
480316350Sbapt
481316350Sbapt	fuse_invalidate_attr(fdvp);
482136638Swollman	if (tdvp != fdvp) {
48320094Swollman		fuse_invalidate_attr(tdvp);
484136638Swollman	}
48593799Swollman	return err;
486316350Sbapt}
487316350Sbapt
488316350Sbapt/* strategy */
489316350Sbapt
490316350Sbapt/* entity creation */
491316350Sbapt
492316350Sbaptvoid
493316350Sbaptfuse_internal_newentry_makerequest(struct mount *mp,
494316350Sbapt    uint64_t dnid,
495316350Sbapt    struct componentname *cnp,
496316350Sbapt    enum fuse_opcode op,
49720094Swollman    void *buf,
498149514Swollman    size_t bufsize,
499136638Swollman    struct fuse_dispatcher *fdip)
50093799Swollman{
501316350Sbapt	debug_printf("fdip=%p\n", fdip);
502316350Sbapt
503316350Sbapt	fdip->iosize = bufsize + cnp->cn_namelen + 1;
504316350Sbapt
505316350Sbapt	fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred);
506316350Sbapt	memcpy(fdip->indata, buf, bufsize);
507316350Sbapt	memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
508316350Sbapt	((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
509316350Sbapt}
510316350Sbapt
51120094Swollmanint
51220094Swollmanfuse_internal_newentry_core(struct vnode *dvp,
513136638Swollman    struct vnode **vpp,
51493799Swollman    struct componentname *cnp,
515316350Sbapt    enum vtype vtyp,
516316350Sbapt    struct fuse_dispatcher *fdip)
517316350Sbapt{
518316350Sbapt	int err = 0;
519316350Sbapt	struct fuse_entry_out *feo;
520316350Sbapt	struct mount *mp = vnode_mount(dvp);
521316350Sbapt
522316350Sbapt	if ((err = fdisp_wait_answ(fdip))) {
523316350Sbapt		return err;
524316350Sbapt	}
525316350Sbapt	feo = fdip->answ;
526316350Sbapt
527316350Sbapt	if ((err = fuse_internal_checkentry(feo, vtyp))) {
528316350Sbapt		return err;
529136638Swollman	}
530177591Sedwin	err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, vtyp);
531198515Sedwin	if (err) {
532206868Sedwin		fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred,
533331663Sphilip		    feo->nodeid, 1);
534198515Sedwin		return err;
535177591Sedwin	}
536177591Sedwin	cache_attrs(*vpp, feo);
537316350Sbapt
538316350Sbapt	return err;
539316350Sbapt}
540316350Sbapt
541316350Sbaptint
542316350Sbaptfuse_internal_newentry(struct vnode *dvp,
543316350Sbapt    struct vnode **vpp,
544316350Sbapt    struct componentname *cnp,
545316350Sbapt    enum fuse_opcode op,
546316350Sbapt    void *buf,
547316350Sbapt    size_t bufsize,
548316350Sbapt    enum vtype vtype)
549316350Sbapt{
550316350Sbapt	int err;
551177591Sedwin	struct fuse_dispatcher fdi;
552136638Swollman	struct mount *mp = vnode_mount(dvp);
553273719Sedwin
554316350Sbapt	fdisp_init(&fdi, 0);
555316350Sbapt	fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
556316350Sbapt	    bufsize, &fdi);
557316350Sbapt	err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi);
558316350Sbapt	fdisp_destroy(&fdi);
559316350Sbapt	fuse_invalidate_attr(dvp);
560316350Sbapt
561316350Sbapt	return err;
562316350Sbapt}
563136638Swollman
564270817Spluknet/* entity destruction */
565273719Sedwin
566316350Sbaptint
567316350Sbaptfuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio)
568316350Sbapt{
569316350Sbapt	fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL,
570316350Sbapt	    ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1);
571316350Sbapt
572316350Sbapt	return 0;
573316350Sbapt}
574316350Sbapt
5758029Swollmanvoid
57614343Swollmanfuse_internal_forget_send(struct mount *mp,
577257697Sedwin    struct thread *td,
57814343Swollman    struct ucred *cred,
5792742Swollman    uint64_t nodeid,
5802742Swollman    uint64_t nlookup)
5812742Swollman{
58286222Swollman
583328476Sphilip	struct fuse_dispatcher fdi;
584316350Sbapt	struct fuse_forget_in *ffi;
5852742Swollman
5862742Swollman	debug_printf("mp=%p, nodeid=%ju, nlookup=%ju\n",
5872742Swollman	    mp, (uintmax_t)nodeid, (uintmax_t)nlookup);
588149514Swollman
5892742Swollman	/*
5902742Swollman         * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
5912742Swollman         *         (long long unsigned) nodeid));
5922742Swollman         */
5932742Swollman
5942742Swollman	fdisp_init(&fdi, sizeof(*ffi));
59520094Swollman	fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred);
59620094Swollman
597270817Spluknet	ffi = fdi.indata;
598270817Spluknet	ffi->nlookup = nlookup;
59920094Swollman
60020094Swollman	fuse_insert_message(fdi.tick);
60120094Swollman	fdisp_destroy(&fdi);
60220094Swollman}
603270817Spluknet
60420094Swollmanvoid
60520094Swollmanfuse_internal_vnode_disappear(struct vnode *vp)
60620094Swollman{
60720094Swollman	struct fuse_vnode_data *fvdat = VTOFUD(vp);
60820094Swollman
60920094Swollman	ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear");
61020094Swollman	fvdat->flag |= FN_REVOKED;
61120094Swollman	cache_purge(vp);
61220094Swollman}
61320094Swollman
61420094Swollman/* fuse start/stop */
61520094Swollman
61620094Swollmanint
617270817Spluknetfuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
618270817Spluknet{
619270817Spluknet	int err = 0;
62020094Swollman	struct fuse_data *data = tick->tk_data;
62143014Swollman	struct fuse_init_out *fiio;
622270817Spluknet
62375267Swollman	if ((err = tick->tk_aw_ohead.error)) {
624270817Spluknet		goto out;
62575267Swollman	}
62675267Swollman	if ((err = fticket_pull(tick, uio))) {
62775267Swollman		goto out;
62875267Swollman	}
629105196Swollman	fiio = fticket_resp(tick)->base;
630105196Swollman
631105196Swollman	/* XXX: Do we want to check anything further besides this? */
632105196Swollman	if (fiio->major < 7) {
633105196Swollman		debug_printf("userpace version too low\n");
634105196Swollman		err = EPROTONOSUPPORT;
635105196Swollman		goto out;
636105196Swollman	}
637105196Swollman	data->fuse_libabi_major = fiio->major;
638105196Swollman	data->fuse_libabi_minor = fiio->minor;
639105196Swollman
640105196Swollman	if (fuse_libabi_geq(data, 7, 5)) {
641105196Swollman		if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) {
642105196Swollman			data->max_write = fiio->max_write;
643105196Swollman		} else {
644105196Swollman			err = EINVAL;
645105196Swollman		}
646136638Swollman	} else {
647136638Swollman		/* Old fix values */
648136638Swollman		data->max_write = 4096;
649136638Swollman	}
650136638Swollman
651172479Sedwinout:
652172479Sedwin	if (err) {
653172479Sedwin		fdata_set_dead(data);
654172479Sedwin	}
655181421Sedwin	FUSE_LOCK();
656181421Sedwin	data->dataflags |= FSESS_INITED;
657270817Spluknet	wakeup(&data->ticketer);
658181421Sedwin	FUSE_UNLOCK();
659181421Sedwin
660273719Sedwin	return 0;
661181421Sedwin}
662181421Sedwin
663270817Spluknetvoid
664181421Sedwinfuse_internal_send_init(struct fuse_data *data, struct thread *td)
665181421Sedwin{
666181421Sedwin	struct fuse_init_in *fiii;
667181421Sedwin	struct fuse_dispatcher fdi;
668181421Sedwin
669181421Sedwin	fdisp_init(&fdi, sizeof(*fiii));
670181421Sedwin	fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL);
671181421Sedwin	fiii = fdi.indata;
672181421Sedwin	fiii->major = FUSE_KERNEL_VERSION;
673181421Sedwin	fiii->minor = FUSE_KERNEL_MINOR_VERSION;
674181421Sedwin	fiii->max_readahead = FUSE_DEFAULT_IOSIZE * 16;
675181421Sedwin	fiii->flags = 0;
676192886Sedwin
677181421Sedwin	fuse_insert_callback(fdi.tick, fuse_internal_init_callback);
678181421Sedwin	fuse_insert_message(fdi.tick);
679181421Sedwin	fdisp_destroy(&fdi);
680270817Spluknet}
681181421Sedwin
682181421Sedwin#ifdef ZERO_PAD_INCOMPLETE_BUFS
683181421Sedwinstatic int
684181421Sedwinisbzero(void *buf, size_t len)
685181421Sedwin{
686181421Sedwin	int i;
687181421Sedwin
688181421Sedwin	for (i = 0; i < len; i++) {
689181421Sedwin		if (((char *)buf)[i])
690181421Sedwin			return (0);
691270817Spluknet	}
692270817Spluknet
693270817Spluknet	return (1);
694181421Sedwin}
695105196Swollman
696105196Swollman#endif
697273719Sedwin