xref: /freebsd/sys/fs/fuse/fuse_vnops.c (revision 0bd6348b52e1991fafc55128173c989dab36dfd9)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2007-2009 Google Inc. and Amit Singh
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  *   copyright notice, this list of conditions and the following disclaimer
15  *   in the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of Google Inc. nor the names of its
18  *   contributors may be used to endorse or promote products derived from
19  *   this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Copyright (C) 2005 Csaba Henk.
34  * All rights reserved.
35  *
36  * Copyright (c) 2019 The FreeBSD Foundation
37  *
38  * Portions of this software were developed by BFF Storage Systems, LLC under
39  * sponsorship from the FreeBSD Foundation.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  *
50  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  */
62 
63 #include <sys/param.h>
64 #include <sys/module.h>
65 #include <sys/systm.h>
66 #include <sys/errno.h>
67 #include <sys/kernel.h>
68 #include <sys/conf.h>
69 #include <sys/filio.h>
70 #include <sys/uio.h>
71 #include <sys/malloc.h>
72 #include <sys/queue.h>
73 #include <sys/limits.h>
74 #include <sys/lock.h>
75 #include <sys/rwlock.h>
76 #include <sys/sx.h>
77 #include <sys/proc.h>
78 #include <sys/mount.h>
79 #include <sys/vnode.h>
80 #include <sys/namei.h>
81 #include <sys/extattr.h>
82 #include <sys/stat.h>
83 #include <sys/unistd.h>
84 #include <sys/filedesc.h>
85 #include <sys/file.h>
86 #include <sys/fcntl.h>
87 #include <sys/dirent.h>
88 #include <sys/bio.h>
89 #include <sys/buf.h>
90 #include <sys/sysctl.h>
91 #include <sys/vmmeter.h>
92 #define EXTERR_CATEGORY EXTERR_CAT_FUSE_VNOPS
93 #include <sys/exterrvar.h>
94 #include <sys/sysent.h>
95 
96 #include <vm/vm.h>
97 #include <vm/vm_extern.h>
98 #include <vm/pmap.h>
99 #include <vm/vm_map.h>
100 #include <vm/vm_page.h>
101 #include <vm/vm_param.h>
102 #include <vm/vm_object.h>
103 #include <vm/vm_pager.h>
104 #include <vm/vnode_pager.h>
105 #include <vm/vm_object.h>
106 
107 #include "fuse.h"
108 #include "fuse_file.h"
109 #include "fuse_internal.h"
110 #include "fuse_ipc.h"
111 #include "fuse_node.h"
112 #include "fuse_io.h"
113 
114 #include <sys/priv.h>
115 
116 /* Maximum number of hardlinks to a single FUSE file */
117 #define FUSE_LINK_MAX                      UINT32_MAX
118 
119 SDT_PROVIDER_DECLARE(fusefs);
120 /*
121  * Fuse trace probe:
122  * arg0: verbosity.  Higher numbers give more verbose messages
123  * arg1: Textual message
124  */
125 SDT_PROBE_DEFINE2(fusefs, , vnops, trace, "int", "char*");
126 
127 /* vnode ops */
128 static vop_access_t fuse_vnop_access;
129 static vop_advlock_t fuse_vnop_advlock;
130 static vop_allocate_t fuse_vnop_allocate;
131 static vop_bmap_t fuse_vnop_bmap;
132 static vop_close_t fuse_fifo_close;
133 static vop_close_t fuse_vnop_close;
134 static vop_copy_file_range_t fuse_vnop_copy_file_range;
135 static vop_create_t fuse_vnop_create;
136 static vop_deallocate_t fuse_vnop_deallocate;
137 static vop_delayed_setsize_t fuse_vnop_delayed_setsize;
138 static vop_deleteextattr_t fuse_vnop_deleteextattr;
139 static vop_fdatasync_t fuse_vnop_fdatasync;
140 static vop_fsync_t fuse_vnop_fsync;
141 static vop_getattr_t fuse_vnop_getattr;
142 static vop_getextattr_t fuse_vnop_getextattr;
143 static vop_inactive_t fuse_vnop_inactive;
144 static vop_ioctl_t fuse_vnop_ioctl;
145 static vop_link_t fuse_vnop_link;
146 static vop_listextattr_t fuse_vnop_listextattr;
147 static vop_lookup_t fuse_vnop_lookup;
148 static vop_mkdir_t fuse_vnop_mkdir;
149 static vop_mknod_t fuse_vnop_mknod;
150 static vop_open_t fuse_vnop_open;
151 static vop_pathconf_t fuse_vnop_pathconf;
152 static vop_read_t fuse_vnop_read;
153 static vop_readdir_t fuse_vnop_readdir;
154 static vop_readlink_t fuse_vnop_readlink;
155 static vop_reclaim_t fuse_vnop_reclaim;
156 static vop_remove_t fuse_vnop_remove;
157 static vop_rename_t fuse_vnop_rename;
158 static vop_rmdir_t fuse_vnop_rmdir;
159 static vop_setattr_t fuse_vnop_setattr;
160 static vop_setextattr_t fuse_vnop_setextattr;
161 static vop_strategy_t fuse_vnop_strategy;
162 static vop_symlink_t fuse_vnop_symlink;
163 static vop_write_t fuse_vnop_write;
164 static vop_getpages_t fuse_vnop_getpages;
165 static vop_print_t fuse_vnop_print;
166 static vop_vptofh_t fuse_vnop_vptofh;
167 
168 struct vop_vector fuse_fifoops = {
169 	.vop_default =		&fifo_specops,
170 	.vop_access =		fuse_vnop_access,
171 	.vop_close =		fuse_fifo_close,
172 	.vop_fsync =		fuse_vnop_fsync,
173 	.vop_getattr =		fuse_vnop_getattr,
174 	.vop_inactive =		fuse_vnop_inactive,
175 	.vop_pathconf =		fuse_vnop_pathconf,
176 	.vop_print =		fuse_vnop_print,
177 	.vop_read =		VOP_PANIC,
178 	.vop_reclaim =		fuse_vnop_reclaim,
179 	.vop_setattr =		fuse_vnop_setattr,
180 	.vop_write =		VOP_PANIC,
181 	.vop_vptofh =		fuse_vnop_vptofh,
182 };
183 VFS_VOP_VECTOR_REGISTER(fuse_fifoops);
184 
185 struct vop_vector fuse_vnops = {
186 	.vop_allocate =	fuse_vnop_allocate,
187 	.vop_default = &default_vnodeops,
188 	.vop_access = fuse_vnop_access,
189 	.vop_advlock = fuse_vnop_advlock,
190 	.vop_bmap = fuse_vnop_bmap,
191 	.vop_close = fuse_vnop_close,
192 	.vop_copy_file_range = fuse_vnop_copy_file_range,
193 	.vop_create = fuse_vnop_create,
194 	.vop_deallocate = fuse_vnop_deallocate,
195 	.vop_delayed_setsize = fuse_vnop_delayed_setsize,
196 	.vop_deleteextattr = fuse_vnop_deleteextattr,
197 	.vop_fsync = fuse_vnop_fsync,
198 	.vop_fdatasync = fuse_vnop_fdatasync,
199 	.vop_getattr = fuse_vnop_getattr,
200 	.vop_getextattr = fuse_vnop_getextattr,
201 	.vop_inactive = fuse_vnop_inactive,
202 	.vop_ioctl = fuse_vnop_ioctl,
203 	.vop_link = fuse_vnop_link,
204 	.vop_listextattr = fuse_vnop_listextattr,
205 	.vop_lookup = fuse_vnop_lookup,
206 	.vop_mkdir = fuse_vnop_mkdir,
207 	.vop_mknod = fuse_vnop_mknod,
208 	.vop_open = fuse_vnop_open,
209 	.vop_pathconf = fuse_vnop_pathconf,
210 	/*
211 	 * TODO: implement vop_poll after upgrading to protocol 7.21.
212 	 * FUSE_POLL was added in protocol 7.11, but it's kind of broken until
213 	 * 7.21, which adds the ability for the client to choose which poll
214 	 * events it wants, and for a client to deregister a file handle
215 	 */
216 	.vop_read = fuse_vnop_read,
217 	.vop_readdir = fuse_vnop_readdir,
218 	.vop_readlink = fuse_vnop_readlink,
219 	.vop_reclaim = fuse_vnop_reclaim,
220 	.vop_remove = fuse_vnop_remove,
221 	.vop_rename = fuse_vnop_rename,
222 	.vop_rmdir = fuse_vnop_rmdir,
223 	.vop_setattr = fuse_vnop_setattr,
224 	.vop_setextattr = fuse_vnop_setextattr,
225 	.vop_strategy = fuse_vnop_strategy,
226 	.vop_symlink = fuse_vnop_symlink,
227 	.vop_write = fuse_vnop_write,
228 	.vop_getpages = fuse_vnop_getpages,
229 	.vop_print = fuse_vnop_print,
230 	.vop_vptofh = fuse_vnop_vptofh,
231 };
232 VFS_VOP_VECTOR_REGISTER(fuse_vnops);
233 
234 /* Check permission for extattr operations, much like extattr_check_cred */
235 static int
236 fuse_extattr_check_cred(struct vnode *vp, int ns, struct ucred *cred,
237 	struct thread *td, accmode_t accmode)
238 {
239 	struct mount *mp = vnode_mount(vp);
240 	struct fuse_data *data = fuse_get_mpdata(mp);
241 	int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS;
242 
243 	/*
244 	 * Kernel-invoked always succeeds.
245 	 */
246 	if (cred == NOCRED)
247 		return (0);
248 
249 	/*
250 	 * Do not allow privileged processes in jail to directly manipulate
251 	 * system attributes.
252 	 */
253 	switch (ns) {
254 	case EXTATTR_NAMESPACE_SYSTEM:
255 		if (default_permissions) {
256 			return (priv_check_cred(cred, PRIV_VFS_EXTATTR_SYSTEM));
257 		}
258 		return (0);
259 	case EXTATTR_NAMESPACE_USER:
260 		if (default_permissions) {
261 			return (fuse_internal_access(vp, accmode, td, cred));
262 		}
263 		return (0);
264 	default:
265 		return (EPERM);
266 	}
267 }
268 
269 /* Send FUSE_FLUSH for this vnode */
270 static int
271 fuse_flush(struct vnode *vp, struct ucred *cred, pid_t pid, int fflag)
272 {
273 	struct fuse_flush_in *ffi;
274 	struct fuse_filehandle *fufh;
275 	struct fuse_dispatcher fdi;
276 	struct thread *td = curthread;
277 	struct mount *mp = vnode_mount(vp);
278 	int err;
279 
280 	if (fsess_not_impl(mp, FUSE_FLUSH))
281 		return 0;
282 
283 	err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
284 	if (err)
285 		return err;
286 
287 	if (fufh->fuse_open_flags & FOPEN_NOFLUSH &&
288 	    (!fsess_opt_writeback(mp)))
289 		return (0);
290 
291 	fdisp_init(&fdi, sizeof(*ffi));
292 	fdisp_make_vp(&fdi, FUSE_FLUSH, vp, td, cred);
293 	ffi = fdi.indata;
294 	ffi->fh = fufh->fh_id;
295 	/*
296 	 * If the file has a POSIX lock then we're supposed to set lock_owner.
297 	 * If not, then lock_owner is undefined.  So we may as well always set
298 	 * it.
299 	 */
300 	ffi->lock_owner = td->td_proc->p_pid;
301 
302 	err = fdisp_wait_answ(&fdi);
303 	if (err == ENOSYS) {
304 		fsess_set_notimpl(mp, FUSE_FLUSH);
305 		err = 0;
306 	}
307 	fdisp_destroy(&fdi);
308 	return err;
309 }
310 
311 /* Close wrapper for fifos.  */
312 static int
313 fuse_fifo_close(struct vop_close_args *ap)
314 {
315 	return (fifo_specops.vop_close(ap));
316 }
317 
318 /* Invalidate a range of cached data, whether dirty of not */
319 static int
320 fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end,
321 	int slpflag)
322 {
323 	struct buf *bp;
324 	daddr_t left_lbn, end_lbn, right_lbn;
325 	off_t new_filesize;
326 	int iosize, left_on, right_on, right_blksize;
327 
328 	iosize = fuse_iosize(vp);
329 	left_lbn = start / iosize;
330 	end_lbn = howmany(end, iosize);
331 	left_on = start & (iosize - 1);
332 	if (left_on != 0) {
333 		bp = getblk(vp, left_lbn, iosize, slpflag, 0, 0);
334 		if (!bp)
335 			return (EINTR);
336 		if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyend >= left_on) {
337 			/*
338 			 * Flush the dirty buffer, because we don't have a
339 			 * byte-granular way to record which parts of the
340 			 * buffer are valid.
341 			 */
342 			bwrite(bp);
343 			if (bp->b_error)
344 				return (bp->b_error);
345 		} else {
346 			brelse(bp);
347 		}
348 	}
349 	right_on = end & (iosize - 1);
350 	if (right_on != 0) {
351 		right_lbn = end / iosize;
352 		new_filesize = MAX(filesize, end);
353 		right_blksize = MIN(iosize, new_filesize - iosize * right_lbn);
354 		bp = getblk(vp, right_lbn, right_blksize, slpflag, 0, 0);
355 		if (!bp)
356 			return (EINTR);
357 		if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyoff < right_on) {
358 			/*
359 			 * Flush the dirty buffer, because we don't have a
360 			 * byte-granular way to record which parts of the
361 			 * buffer are valid.
362 			 */
363 			bwrite(bp);
364 			if (bp->b_error)
365 				return (bp->b_error);
366 		} else {
367 			brelse(bp);
368 		}
369 	}
370 
371 	v_inval_buf_range(vp, left_lbn, end_lbn, iosize);
372 	return (0);
373 }
374 
375 /* Send FUSE_IOCTL for this node */
376 static int
377 fuse_vnop_do_ioctl(struct vnode *vp, u_long cmd, void *arg, int fflag,
378 	struct ucred *cred, struct thread *td)
379 {
380 	struct fuse_dispatcher fdi;
381 	struct fuse_ioctl_in *fii;
382 	struct fuse_ioctl_out *fio;
383 	struct fuse_filehandle *fufh;
384 	uint32_t flags = 0;
385 	uint32_t insize = 0;
386 	uint32_t outsize = 0;
387 	int err;
388 
389 	err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, td->td_proc->p_pid);
390 	if (err != 0)
391 		return (err);
392 
393 	if (vnode_isdir(vp)) {
394 		struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
395 
396 		if (!fuse_libabi_geq(data, 7, 18))
397 			return (ENOTTY);
398 		flags |= FUSE_IOCTL_DIR;
399 	}
400 #ifdef __LP64__
401 #ifdef COMPAT_FREEBSD32
402 	if (SV_PROC_FLAG(td->td_proc, SV_ILP32))
403 		flags |= FUSE_IOCTL_32BIT;
404 #endif
405 #else /* !defined(__LP64__) */
406 	flags |= FUSE_IOCTL_32BIT;
407 #endif
408 
409 	if ((cmd & IOC_OUT) != 0)
410 		outsize = IOCPARM_LEN(cmd);
411 	/* _IOWINT() sets IOC_VOID */
412 	if ((cmd & (IOC_VOID | IOC_IN)) != 0)
413 		insize = IOCPARM_LEN(cmd);
414 
415 	fdisp_init(&fdi, sizeof(*fii) + insize);
416 	fdisp_make_vp(&fdi, FUSE_IOCTL, vp, td, cred);
417 	fii = fdi.indata;
418 	fii->fh = fufh->fh_id;
419 	fii->flags = flags;
420 	fii->cmd = cmd;
421 	fii->arg = (uintptr_t)arg;
422 	fii->in_size = insize;
423 	fii->out_size = outsize;
424 	if (insize > 0)
425 		memcpy((char *)fii + sizeof(*fii), arg, insize);
426 
427 	err = fdisp_wait_answ(&fdi);
428 	if (err != 0) {
429 		if (err == ENOSYS)
430 			err = ENOTTY;
431 		goto out;
432 	}
433 
434 	fio = fdi.answ;
435 	if (fdi.iosize > sizeof(*fio)) {
436 		size_t realoutsize = fdi.iosize - sizeof(*fio);
437 
438 		if (realoutsize > outsize) {
439 			err = EIO;
440 			goto out;
441 		}
442 		memcpy(arg, (char *)fio + sizeof(*fio), realoutsize);
443 	}
444 	if (fio->result > 0)
445 		td->td_retval[0] = fio->result;
446 	else
447 		err = -fio->result;
448 
449 out:
450 	fdisp_destroy(&fdi);
451 	return (err);
452 }
453 
454 /* Send FUSE_LSEEK for this node */
455 static int
456 fuse_vnop_do_lseek(struct vnode *vp, struct thread *td, struct ucred *cred,
457 	pid_t pid, off_t *offp, int whence)
458 {
459 	struct fuse_dispatcher fdi;
460 	struct fuse_filehandle *fufh;
461 	struct fuse_lseek_in *flsi;
462 	struct fuse_lseek_out *flso;
463 	struct mount *mp = vnode_mount(vp);
464 	int err;
465 
466 	ASSERT_VOP_LOCKED(vp, __func__);
467 
468 	err = fuse_filehandle_getrw(vp, FREAD, &fufh, cred, pid);
469 	if (err)
470 		return (err);
471 	fdisp_init(&fdi, sizeof(*flsi));
472 	fdisp_make_vp(&fdi, FUSE_LSEEK, vp, td, cred);
473 	flsi = fdi.indata;
474 	flsi->fh = fufh->fh_id;
475 	flsi->offset = *offp;
476 	flsi->whence = whence;
477 	err = fdisp_wait_answ(&fdi);
478 	if (err == ENOSYS) {
479 		fsess_set_notimpl(mp, FUSE_LSEEK);
480 	} else if (err == ENXIO) {
481 		/* Note: ENXIO means "no more hole/data regions until EOF" */
482 		fsess_set_impl(mp, FUSE_LSEEK);
483 	} else if (err == 0) {
484 		fsess_set_impl(mp, FUSE_LSEEK);
485 		flso = fdi.answ;
486 		*offp = flso->offset;
487 	}
488 	fdisp_destroy(&fdi);
489 
490 	return (err);
491 }
492 
493 /*
494     struct vnop_access_args {
495 	struct vnode *a_vp;
496 #if VOP_ACCESS_TAKES_ACCMODE_T
497 	accmode_t a_accmode;
498 #else
499 	int a_mode;
500 #endif
501 	struct ucred *a_cred;
502 	struct thread *a_td;
503     };
504 */
505 static int
506 fuse_vnop_access(struct vop_access_args *ap)
507 {
508 	struct vnode *vp = ap->a_vp;
509 	int accmode = ap->a_accmode;
510 	int err;
511 
512 	if (fuse_isdeadfs(vp)) {
513 		if (vnode_isvroot(vp)) {
514 			return 0;
515 		}
516 		return (EXTERROR(ENXIO, "This FUSE session is about "
517 		    "to be closed"));
518 	}
519 	if (vnode_islnk(vp)) {
520 		return 0;
521 	}
522 
523 	err = fuse_internal_access(vp, accmode, ap->a_td, ap->a_cred);
524 	return err;
525 }
526 
527 /*
528  * struct vop_advlock_args {
529  *	struct vop_generic_args a_gen;
530  *	struct vnode *a_vp;
531  *	void *a_id;
532  *	int a_op;
533  *	struct flock *a_fl;
534  *	int a_flags;
535  * }
536  */
537 static int
538 fuse_vnop_advlock(struct vop_advlock_args *ap)
539 {
540 	struct vnode *vp = ap->a_vp;
541 	struct flock *fl = ap->a_fl;
542 	struct thread *td = curthread;
543 	struct ucred *cred = td->td_ucred;
544 	pid_t pid = td->td_proc->p_pid;
545 	struct fuse_filehandle *fufh;
546 	struct fuse_dispatcher fdi;
547 	struct fuse_lk_in *fli;
548 	struct fuse_lk_out *flo;
549 	struct vattr vattr;
550 	enum fuse_opcode op;
551 	off_t size, start;
552 	int dataflags, err;
553 	int flags = ap->a_flags;
554 
555 	dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
556 
557 	if (fuse_isdeadfs(vp)) {
558 		return (EXTERROR(ENXIO, "This FUSE session is about "
559 		    "to be closed"));
560 	}
561 
562 	switch(ap->a_op) {
563 	case F_GETLK:
564 		op = FUSE_GETLK;
565 		break;
566 	case F_SETLK:
567 		if (flags & F_WAIT)
568 			op = FUSE_SETLKW;
569 		else
570 			op = FUSE_SETLK;
571 		break;
572 	case F_UNLCK:
573 		op = FUSE_SETLK;
574 		break;
575 	default:
576 		return (EXTERROR(EINVAL, "Unsupported lock flags"));
577 	}
578 
579 	if (!(dataflags & FSESS_POSIX_LOCKS))
580 		return vop_stdadvlock(ap);
581 	/* FUSE doesn't properly support flock until protocol 7.17 */
582 	if (flags & F_FLOCK)
583 		return vop_stdadvlock(ap);
584 
585 	vn_lock(vp, LK_SHARED | LK_RETRY);
586 
587 	switch (fl->l_whence) {
588 	case SEEK_SET:
589 	case SEEK_CUR:
590 		/*
591 		 * Caller is responsible for adding any necessary offset
592 		 * when SEEK_CUR is used.
593 		 */
594 		start = fl->l_start;
595 		break;
596 
597 	case SEEK_END:
598 		err = fuse_internal_getattr(vp, &vattr, cred, td);
599 		if (err)
600 			goto out;
601 		size = vattr.va_size;
602 		if (size > OFF_MAX ||
603 		    (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) {
604 			err = EXTERROR(EOVERFLOW, "Offset is too large");
605 			goto out;
606 		}
607 		start = size + fl->l_start;
608 		break;
609 
610 	default:
611 		return (EXTERROR(EINVAL, "Unsupported offset type"));
612 	}
613 
614 	err = fuse_filehandle_get_anyflags(vp, &fufh, cred, pid);
615 	if (err)
616 		goto out;
617 
618 	fdisp_init(&fdi, sizeof(*fli));
619 
620 	fdisp_make_vp(&fdi, op, vp, td, cred);
621 	fli = fdi.indata;
622 	fli->fh = fufh->fh_id;
623 	fli->owner = td->td_proc->p_pid;
624 	fli->lk.start = start;
625 	if (fl->l_len != 0)
626 		fli->lk.end = start + fl->l_len - 1;
627 	else
628 		fli->lk.end = INT64_MAX;
629 	fli->lk.type = fl->l_type;
630 	fli->lk.pid = td->td_proc->p_pid;
631 
632 	err = fdisp_wait_answ(&fdi);
633 	fdisp_destroy(&fdi);
634 
635 	if (err == 0 && op == FUSE_GETLK) {
636 		flo = fdi.answ;
637 		fl->l_type = flo->lk.type;
638 		fl->l_whence = SEEK_SET;
639 		if (flo->lk.type != F_UNLCK) {
640 			fl->l_pid = flo->lk.pid;
641 			fl->l_start = flo->lk.start;
642 			if (flo->lk.end == INT64_MAX)
643 				fl->l_len = 0;
644 			else
645 				fl->l_len = flo->lk.end - flo->lk.start + 1;
646 			fl->l_start = flo->lk.start;
647 		}
648 	}
649 
650 out:
651 	VOP_UNLOCK(vp);
652 	return err;
653 }
654 
655 static int
656 fuse_vnop_allocate(struct vop_allocate_args *ap)
657 {
658 	struct vnode *vp = ap->a_vp;
659 	off_t *len = ap->a_len;
660 	off_t *offset = ap->a_offset;
661 	struct ucred *cred = ap->a_cred;
662 	struct fuse_filehandle *fufh;
663 	struct mount *mp = vnode_mount(vp);
664 	struct fuse_dispatcher fdi;
665 	struct fuse_fallocate_in *ffi;
666 	struct uio io;
667 	pid_t pid = curthread->td_proc->p_pid;
668 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
669 	off_t filesize;
670 	int err;
671 
672 	if (fuse_isdeadfs(vp))
673 		return (EXTERROR(ENXIO, "This FUSE session is about "
674 		    "to be closed"));
675 
676 	switch (vp->v_type) {
677 	case VFIFO:
678 		return (ESPIPE);
679 	case VLNK:
680 	case VREG:
681 		break;
682 	default:
683 		return (ENODEV);
684 	}
685 
686 	if (vfs_isrdonly(mp))
687 		return (EROFS);
688 
689 	if (fsess_not_impl(mp, FUSE_FALLOCATE))
690 		return (EXTERROR(EOPNOTSUPP, "This server does not implement "
691 		    "FUSE_FALLOCATE"));
692 
693 	ASSERT_CACHED_ATTRS_LOCKED(vp);
694 
695 	io.uio_offset = *offset;
696 	io.uio_resid = *len;
697 	err = vn_rlimit_fsize(vp, &io, curthread);
698 	if (err)
699 		return (err);
700 
701 	err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
702 	if (err)
703 		return (err);
704 
705 	fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
706 
707 	err = fuse_vnode_size(vp, &filesize, cred, curthread);
708 	if (err)
709 		return (err);
710 	err = fuse_inval_buf_range(vp, filesize, *offset, *offset + *len,
711 	    PCATCH);
712 	if (err)
713 		return (err);
714 
715 	fdisp_init(&fdi, sizeof(*ffi));
716 	fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred);
717 	ffi = fdi.indata;
718 	ffi->fh = fufh->fh_id;
719 	ffi->offset = *offset;
720 	ffi->length = *len;
721 	ffi->mode = 0;
722 	err = fdisp_wait_answ(&fdi);
723 
724 	if (err == ENOSYS) {
725 		fsess_set_notimpl(mp, FUSE_FALLOCATE);
726 		err = EXTERROR(EOPNOTSUPP, "This server does not implement "
727 		    "FUSE_ALLOCATE");
728 	} else if (err == EOPNOTSUPP) {
729 		/*
730 		 * The file system server does not support FUSE_FALLOCATE with
731 		 * the supplied mode for this particular file.
732 		 */
733 		err = EXTERROR(EOPNOTSUPP, "This file can't be pre-allocated");
734 	} else if (!err) {
735 		*offset += *len;
736 		*len = 0;
737 		fuse_vnode_undirty_cached_timestamps(vp, false);
738 		fuse_internal_clear_suid_on_write(vp, cred, curthread);
739 		if (*offset > fvdat->cached_attrs.va_size) {
740 			fuse_vnode_setsize(vp, *offset, false);
741 			getnanouptime(&fvdat->last_local_modify);
742 		}
743 	}
744 
745 	fdisp_destroy(&fdi);
746 	return (err);
747 }
748 
749 /* {
750 	struct vnode *a_vp;
751 	daddr_t a_bn;
752 	struct bufobj **a_bop;
753 	daddr_t *a_bnp;
754 	int *a_runp;
755 	int *a_runb;
756 } */
757 static int
758 fuse_vnop_bmap(struct vop_bmap_args *ap)
759 {
760 	struct vnode *vp = ap->a_vp;
761 	struct bufobj **bo = ap->a_bop;
762 	struct thread *td = curthread;
763 	struct mount *mp;
764 	struct fuse_dispatcher fdi;
765 	struct fuse_bmap_in *fbi;
766 	struct fuse_bmap_out *fbo;
767 	struct fuse_data *data;
768 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
769 	uint64_t biosize;
770 	off_t fsize = VNOVAL;
771 	daddr_t lbn = ap->a_bn;
772 	daddr_t *pbn = ap->a_bnp;
773 	int *runp = ap->a_runp;
774 	int *runb = ap->a_runb;
775 	int error = 0;
776 	int maxrun;
777 
778 	if (fuse_isdeadfs(vp)) {
779 		return (EXTERROR(ENXIO, "This FUSE session is about "
780 		    "to be closed"));
781 	}
782 
783 	mp = vnode_mount(vp);
784 	data = fuse_get_mpdata(mp);
785 	biosize = fuse_iosize(vp);
786 	maxrun = MIN(vp->v_mount->mnt_iosize_max / biosize - 1,
787 		data->max_readahead_blocks);
788 
789 	if (bo != NULL)
790 		*bo = &vp->v_bufobj;
791 
792 	/*
793 	 * The FUSE_BMAP operation does not include the runp and runb
794 	 * variables, so we must guess.  Report nonzero contiguous runs so
795 	 * cluster_read will combine adjacent reads.  It's worthwhile to reduce
796 	 * upcalls even if we don't know the true physical layout of the file.
797 	 *
798 	 * FUSE file systems may opt out of read clustering in two ways:
799 	 * * mounting with -onoclusterr
800 	 * * Setting max_readahead <= maxbcachebuf during FUSE_INIT
801 	 */
802 	if (runb != NULL)
803 		*runb = MIN(lbn, maxrun);
804 	if (runp != NULL && maxrun == 0)
805 		*runp = 0;
806 	else if (runp != NULL) {
807 		/*
808 		 * If the file's size is cached, use that value to calculate
809 		 * runp, even if the cache is expired.  runp is only advisory,
810 		 * and the risk of getting it wrong is not worth the cost of
811 		 * another upcall.
812 		 */
813 		CACHED_ATTR_LOCK(vp);
814 		fsize = fvdat->cached_attrs.va_size;
815 		CACHED_ATTR_UNLOCK(vp);
816 		if (fsize == VNOVAL)
817 			error = fuse_vnode_size(vp, &fsize, td->td_ucred, td);
818 		if (error == 0)
819 			*runp = MIN(MAX(0, fsize / (off_t)biosize - lbn - 1),
820 				    maxrun);
821 		else
822 			*runp = 0;
823 	}
824 
825 	if (fsess_maybe_impl(mp, FUSE_BMAP)) {
826 		fdisp_init(&fdi, sizeof(*fbi));
827 		fdisp_make_vp(&fdi, FUSE_BMAP, vp, td, td->td_ucred);
828 		fbi = fdi.indata;
829 		fbi->block = lbn;
830 		fbi->blocksize = biosize;
831 		error = fdisp_wait_answ(&fdi);
832 		if (error == ENOSYS) {
833 			fdisp_destroy(&fdi);
834 			fsess_set_notimpl(mp, FUSE_BMAP);
835 			error = 0;
836 		} else {
837 			fbo = fdi.answ;
838 			if (error == 0 && pbn != NULL)
839 				*pbn = fbo->block;
840 			fdisp_destroy(&fdi);
841 			return error;
842 		}
843 	}
844 
845 	/* If the daemon doesn't support BMAP, make up a sensible default */
846 	if (pbn != NULL)
847 		*pbn = lbn * btodb(biosize);
848 	return (error);
849 }
850 
851 /*
852     struct vop_close_args {
853 	struct vnode *a_vp;
854 	int  a_fflag;
855 	struct ucred *a_cred;
856 	struct thread *a_td;
857     };
858 */
859 static int
860 fuse_vnop_close(struct vop_close_args *ap)
861 {
862 	struct vnode *vp = ap->a_vp;
863 	struct mount *mp = vnode_mount(vp);
864 	struct ucred *cred = ap->a_cred;
865 	int fflag = ap->a_fflag;
866 	struct thread *td;
867 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
868 	struct timespec va_atime;
869 	pid_t pid;
870 	int err = 0;
871 	bool atime_change, size_change;
872 
873 	/* NB: a_td will be NULL from some async kernel contexts */
874 	td = ap->a_td ? ap->a_td : curthread;
875 	pid = td->td_proc->p_pid;
876 
877 	if (fuse_isdeadfs(vp))
878 		return 0;
879 	if (vnode_isdir(vp))
880 		return 0;
881 	if (fflag & IO_NDELAY)
882 		return 0;
883 
884 	if (cred == NULL)
885 		cred = td->td_ucred;
886 
887 	err = fuse_flush(vp, cred, pid, fflag);
888 
889 	CACHED_ATTR_LOCK(vp);
890 	atime_change = fvdat->flag & FN_ATIMECHANGE;
891 	size_change = fvdat->flag & FN_SIZECHANGE;
892 	va_atime = fvdat->cached_attrs.va_atime;
893 	CACHED_ATTR_UNLOCK(vp);
894 
895 	if (err == 0 && atime_change && !vfs_isrdonly(mp)) {
896 		struct vattr vap;
897 		struct fuse_data *data;
898 		int dataflags;
899 		int access_e = 0;
900 
901 		data = fuse_get_mpdata(mp);
902 		dataflags = data->dataflags;
903 		if (dataflags & FSESS_DEFAULT_PERMISSIONS) {
904 			struct vattr va;
905 
906 			fuse_internal_getattr(vp, &va, cred, td);
907 			access_e = vaccess(vp->v_type, va.va_mode, va.va_uid,
908 			    va.va_gid, VWRITE, cred);
909 		}
910 		if (access_e == 0) {
911 			VATTR_NULL(&vap);
912 			vap.va_atime = va_atime;
913 			/*
914 			 * Ignore errors setting when setting atime.  That
915 			 * should not cause close(2) to fail.
916 			 */
917 			CACHED_ATTR_LOCK(vp);
918 			fuse_internal_setattr(vp, &vap, td, NULL);
919 			CACHED_ATTR_UNLOCK(vp);
920 		}
921 	}
922 	/* TODO: close the file handle, if we're sure it's no longer used */
923 	if (size_change != 0) {
924 		/*
925 		 * NB: this may panic if MNTK_SHARED_WRITES is ever enabled.
926 		 * For now it cannot, because it is illegal to use fexecve to
927 		 * execute a file descriptor open for writing, there's no way
928 		 * to dirty a file's size without writing to it, and we don't
929 		 * set MNTK_SHARED_WRITES.
930 		 */
931 		fuse_vnode_savesize(vp, cred, pid);
932 	}
933 
934 	return err;
935 }
936 
937 /*
938    struct vop_copy_file_range_args {
939 	struct vop_generic_args a_gen;
940 	struct vnode *a_invp;
941 	off_t *a_inoffp;
942 	struct vnode *a_outvp;
943 	off_t *a_outoffp;
944 	size_t *a_lenp;
945 	unsigned int a_flags;
946 	struct ucred *a_incred;
947 	struct ucred *a_outcred;
948 	struct thread *a_fsizetd;
949 }
950  */
951 static int
952 fuse_vnop_copy_file_range(struct vop_copy_file_range_args *ap)
953 {
954 	struct vnode *invp = ap->a_invp;
955 	struct vnode *outvp = ap->a_outvp;
956 	struct mount *mp = vnode_mount(invp);
957 	struct fuse_vnode_data *outfvdat = VTOFUD(outvp);
958 	struct fuse_dispatcher fdi;
959 	struct fuse_filehandle *infufh, *outfufh;
960 	struct fuse_copy_file_range_in *fcfri;
961 	struct ucred *incred = ap->a_incred;
962 	struct ucred *outcred = ap->a_outcred;
963 	struct fuse_write_out *fwo;
964 	struct thread *td;
965 	struct uio io;
966 	off_t outfilesize;
967 	ssize_t r = 0;
968 	pid_t pid;
969 	int err;
970 
971 	if ((ap->a_flags & COPY_FILE_RANGE_CLONE) != 0)
972 		return (EXTERROR(ENOSYS, "Cannot clone"));
973 
974 	if (mp == NULL || mp != vnode_mount(outvp))
975 		return (EXTERROR(ENOSYS, "Mount points do not match"));
976 
977 	if (incred->cr_uid != outcred->cr_uid)
978 		return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not "
979 		    "support different credentials for infd and outfd"));
980 
981 	if (incred->cr_gid != outcred->cr_gid)
982 		return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not "
983 		    "support different credentials for infd and outfd"));
984 
985 	/* Caller busied mp, mnt_data can be safely accessed. */
986 	if (fsess_not_impl(mp, FUSE_COPY_FILE_RANGE))
987 		return (EXTERROR(ENOSYS, "This daemon does not "
988 		    "implement COPY_FILE_RANGE"));
989 
990 	if (ap->a_fsizetd == NULL)
991 		td = curthread;
992 	else
993 		td = ap->a_fsizetd;
994 	pid = td->td_proc->p_pid;
995 
996 	vn_lock_pair(invp, false, LK_SHARED, outvp, false, LK_EXCLUSIVE);
997 	if (invp->v_data == NULL || outvp->v_data == NULL) {
998 		err = EXTERROR(EBADF, "vnode got reclaimed");
999 		goto unlock;
1000 	}
1001 
1002 	err = fuse_filehandle_getrw(invp, FREAD, &infufh, incred, pid);
1003 	if (err)
1004 		goto unlock;
1005 
1006 	err = fuse_filehandle_getrw(outvp, FWRITE, &outfufh, outcred, pid);
1007 	if (err)
1008 		goto unlock;
1009 
1010 	io.uio_resid = *ap->a_lenp;
1011 	if (ap->a_fsizetd) {
1012 		io.uio_offset = *ap->a_outoffp;
1013 		err = vn_rlimit_fsizex(outvp, &io, 0, &r, ap->a_fsizetd);
1014 		if (err != 0)
1015 			goto unlock;
1016 	}
1017 
1018 	err = fuse_vnode_size(outvp, &outfilesize, outcred, curthread);
1019 	if (err)
1020 		goto unlock;
1021 
1022 	vnode_pager_clean_sync(invp);
1023 	err = fuse_inval_buf_range(outvp, outfilesize, *ap->a_outoffp,
1024 		*ap->a_outoffp + io.uio_resid, PCATCH);
1025 	if (err)
1026 		goto unlock;
1027 
1028 	fdisp_init(&fdi, sizeof(*fcfri));
1029 	fdisp_make_vp(&fdi, FUSE_COPY_FILE_RANGE, invp, td, incred);
1030 	fcfri = fdi.indata;
1031 	fcfri->fh_in = infufh->fh_id;
1032 	fcfri->off_in = *ap->a_inoffp;
1033 	fcfri->nodeid_out = VTOI(outvp);
1034 	fcfri->fh_out = outfufh->fh_id;
1035 	fcfri->off_out = *ap->a_outoffp;
1036 	fcfri->len = io.uio_resid;
1037 	fcfri->flags = 0;
1038 
1039 	err = fdisp_wait_answ(&fdi);
1040 	if (err == 0) {
1041 		fwo = fdi.answ;
1042 		*ap->a_lenp = fwo->size;
1043 		*ap->a_inoffp += fwo->size;
1044 		*ap->a_outoffp += fwo->size;
1045 		fuse_internal_clear_suid_on_write(outvp, outcred, td);
1046 		ASSERT_CACHED_ATTRS_LOCKED(outvp);
1047 		if (*ap->a_outoffp > outfvdat->cached_attrs.va_size) {
1048 			fuse_vnode_setsize(outvp, *ap->a_outoffp, false);
1049 			getnanouptime(&outfvdat->last_local_modify);
1050 		}
1051 		fuse_vnode_update(invp, FN_ATIMECHANGE);
1052 		fuse_vnode_update(outvp, FN_MTIMECHANGE | FN_CTIMECHANGE);
1053 	}
1054 	fdisp_destroy(&fdi);
1055 
1056 unlock:
1057 	if (invp != outvp)
1058 		VOP_UNLOCK(invp);
1059 	VOP_UNLOCK(outvp);
1060 
1061 	if (err == ENOSYS)
1062 		fsess_set_notimpl(mp, FUSE_COPY_FILE_RANGE);
1063 
1064 	/*
1065 	 * No need to call vn_rlimit_fsizex_res before return, since the uio is
1066 	 * local.
1067 	 */
1068 	return (err);
1069 }
1070 
1071 static void
1072 fdisp_make_mknod_for_fallback(
1073 	struct fuse_dispatcher *fdip,
1074 	struct componentname *cnp,
1075 	struct vnode *dvp,
1076 	uint64_t parentnid,
1077 	struct thread *td,
1078 	struct ucred *cred,
1079 	mode_t mode,
1080 	enum fuse_opcode *op)
1081 {
1082 	struct fuse_mknod_in *fmni;
1083 
1084 	fdisp_init(fdip, sizeof(*fmni) + cnp->cn_namelen + 1);
1085 	*op = FUSE_MKNOD;
1086 	fdisp_make(fdip, *op, vnode_mount(dvp), parentnid, td, cred);
1087 	fmni = fdip->indata;
1088 	fmni->mode = mode;
1089 	fmni->rdev = 0;
1090 	memcpy((char *)fdip->indata + sizeof(*fmni), cnp->cn_nameptr,
1091 	    cnp->cn_namelen);
1092 	((char *)fdip->indata)[sizeof(*fmni) + cnp->cn_namelen] = '\0';
1093 }
1094 /*
1095     struct vnop_create_args {
1096 	struct vnode *a_dvp;
1097 	struct vnode **a_vpp;
1098 	struct componentname *a_cnp;
1099 	struct vattr *a_vap;
1100     };
1101 */
1102 static int
1103 fuse_vnop_create(struct vop_create_args *ap)
1104 {
1105 	struct vnode *dvp = ap->a_dvp;
1106 	struct vnode **vpp = ap->a_vpp;
1107 	struct componentname *cnp = ap->a_cnp;
1108 	struct vattr *vap = ap->a_vap;
1109 	struct thread *td = curthread;
1110 	struct ucred *cred = cnp->cn_cred;
1111 
1112 	struct fuse_data *data;
1113 	struct fuse_create_in *fci;
1114 	struct fuse_entry_out *feo;
1115 	struct fuse_open_out *foo;
1116 	struct fuse_dispatcher fdi, fdi2;
1117 	struct fuse_dispatcher *fdip = &fdi;
1118 	struct fuse_dispatcher *fdip2 = NULL;
1119 
1120 	int err;
1121 
1122 	struct mount *mp = vnode_mount(dvp);
1123 	data = fuse_get_mpdata(mp);
1124 	uint64_t parentnid = VTOFUD(dvp)->nid;
1125 	mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode);
1126 	enum fuse_opcode op;
1127 	int flags;
1128 
1129 	if (fuse_isdeadfs(dvp))
1130 		return (EXTERROR(ENXIO, "This FUSE session is about "
1131 		    "to be closed"));
1132 
1133 	/* FUSE expects sockets to be created with FUSE_MKNOD */
1134 	if (vap->va_type == VSOCK)
1135 		return fuse_internal_mknod(dvp, vpp, cnp, vap);
1136 
1137 	/*
1138 	 * VOP_CREATE doesn't tell us the open(2) flags, so we guess.  Only a
1139 	 * writable mode makes sense, and we might as well include readability
1140 	 * too.
1141 	 */
1142 	flags = O_RDWR;
1143 
1144 	bzero(&fdi, sizeof(fdi));
1145 
1146 	if (vap->va_type != VREG)
1147 		return (EXTERROR(EINVAL, "Only regular files can be created"));
1148 
1149 	if (fsess_not_impl(mp, FUSE_CREATE) || vap->va_type == VSOCK) {
1150 		/* Fallback to FUSE_MKNOD/FUSE_OPEN */
1151 		fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
1152 			cred, mode, &op);
1153 	} else {
1154 		/* Use FUSE_CREATE */
1155 		size_t insize;
1156 
1157 		op = FUSE_CREATE;
1158 		fdisp_init(fdip, sizeof(*fci) + cnp->cn_namelen + 1);
1159 		fdisp_make(fdip, op, vnode_mount(dvp), parentnid, td, cred);
1160 		fci = fdip->indata;
1161 		fci->mode = mode;
1162 		fci->flags = O_CREAT | flags;
1163 		if (fuse_libabi_geq(data, 7, 12)) {
1164 			insize = sizeof(*fci);
1165 			fci->umask = td->td_proc->p_pd->pd_cmask;
1166 		} else {
1167 			insize = sizeof(struct fuse_open_in);
1168 		}
1169 
1170 		memcpy((char *)fdip->indata + insize, cnp->cn_nameptr,
1171 		    cnp->cn_namelen);
1172 		((char *)fdip->indata)[insize + cnp->cn_namelen] = '\0';
1173 	}
1174 
1175 	err = fdisp_wait_answ(fdip);
1176 
1177 	if (err) {
1178 		if (err == ENOSYS && op == FUSE_CREATE) {
1179 			fsess_set_notimpl(mp, FUSE_CREATE);
1180 			fdisp_destroy(fdip);
1181 			fdisp_make_mknod_for_fallback(fdip, cnp, dvp,
1182 				parentnid, td, cred, mode, &op);
1183 			err = fdisp_wait_answ(fdip);
1184 		}
1185 		if (err)
1186 			goto out;
1187 	}
1188 
1189 	feo = fdip->answ;
1190 
1191 	if ((err = fuse_internal_checkentry(feo, vap->va_type))) {
1192 		goto out;
1193 	}
1194 
1195 	if (op == FUSE_CREATE) {
1196 		if (fuse_libabi_geq(data, 7, 9))
1197 			foo = (struct fuse_open_out*)(feo + 1);
1198 		else
1199 			foo = (struct fuse_open_out*)((char*)feo +
1200 				FUSE_COMPAT_ENTRY_OUT_SIZE);
1201 	} else {
1202 		/* Issue a separate FUSE_OPEN */
1203 		struct fuse_open_in *foi;
1204 
1205 		fdip2 = &fdi2;
1206 		fdisp_init(fdip2, sizeof(*foi));
1207 		fdisp_make(fdip2, FUSE_OPEN, vnode_mount(dvp), feo->nodeid, td,
1208 			cred);
1209 		foi = fdip2->indata;
1210 		foi->flags = flags;
1211 		err = fdisp_wait_answ(fdip2);
1212 		if (err)
1213 			goto out;
1214 		foo = fdip2->answ;
1215 	}
1216 	err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vap->va_type);
1217 	if (err) {
1218 		struct fuse_release_in *fri;
1219 		uint64_t nodeid = feo->nodeid;
1220 		uint64_t fh_id = foo->fh;
1221 
1222 		fdisp_destroy(fdip);
1223 		fdisp_init(fdip, sizeof(*fri));
1224 		fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred);
1225 		fri = fdip->indata;
1226 		fri->fh = fh_id;
1227 		fri->flags = flags;
1228 		fuse_insert_callback(fdip->tick, fuse_internal_forget_callback);
1229 		fuse_insert_message(fdip->tick, false);
1230 		goto out;
1231 	}
1232 	ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
1233 	fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid,
1234 		feo->attr_valid_nsec, NULL, true);
1235 
1236 	fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, td, cred, foo);
1237 	fuse_vnode_open(*vpp, foo->open_flags, td);
1238 	/*
1239 	 * Purge the parent's attribute cache because the daemon should've
1240 	 * updated its mtime and ctime
1241 	 */
1242 	fuse_vnode_clear_attr_cache(dvp);
1243 	cache_purge_negative(dvp);
1244 
1245 out:
1246 	if (fdip2)
1247 		fdisp_destroy(fdip2);
1248 	fdisp_destroy(fdip);
1249 	return err;
1250 }
1251 
1252 /*
1253     struct vnop_fdatasync_args {
1254 	struct vop_generic_args a_gen;
1255 	struct vnode * a_vp;
1256 	struct thread * a_td;
1257     };
1258 */
1259 static int
1260 fuse_vnop_fdatasync(struct vop_fdatasync_args *ap)
1261 {
1262 	struct vnode *vp = ap->a_vp;
1263 	struct thread *td = ap->a_td;
1264 	int waitfor = MNT_WAIT;
1265 
1266 	int err = 0;
1267 
1268 	if (fuse_isdeadfs(vp)) {
1269 		return 0;
1270 	}
1271 	if ((err = vop_stdfdatasync_buf(ap)))
1272 		return err;
1273 
1274 	return fuse_internal_fsync(vp, td, waitfor, true);
1275 }
1276 
1277 /*
1278     struct vnop_fsync_args {
1279 	struct vop_generic_args a_gen;
1280 	struct vnode * a_vp;
1281 	int  a_waitfor;
1282 	struct thread * a_td;
1283     };
1284 */
1285 static int
1286 fuse_vnop_fsync(struct vop_fsync_args *ap)
1287 {
1288 	struct vnode *vp = ap->a_vp;
1289 	struct thread *td = ap->a_td;
1290 	int waitfor = ap->a_waitfor;
1291 	int err = 0;
1292 
1293 	if (fuse_isdeadfs(vp)) {
1294 		return 0;
1295 	}
1296 	if ((err = vop_stdfsync(ap)))
1297 		return err;
1298 
1299 	return fuse_internal_fsync(vp, td, waitfor, false);
1300 }
1301 
1302 /*
1303     struct vnop_getattr_args {
1304 	struct vnode *a_vp;
1305 	struct vattr *a_vap;
1306 	struct ucred *a_cred;
1307 	struct thread *a_td;
1308     };
1309 */
1310 static int
1311 fuse_vnop_getattr(struct vop_getattr_args *ap)
1312 {
1313 	struct vnode *vp = ap->a_vp;
1314 	struct vattr *vap = ap->a_vap;
1315 	struct ucred *cred = ap->a_cred;
1316 	struct thread *td = curthread;
1317 	int err = 0;
1318 
1319 	err = fuse_internal_getattr(vp, vap, cred, td);
1320 	if (err == ENOTCONN && vnode_isvroot(vp)) {
1321 		/*
1322 		 * We want to seem a legitimate fs even if the daemon is dead,
1323 		 * so that, eg., we can still do path based unmounting after
1324 		 * the daemon dies.
1325 		 */
1326 		err = 0;
1327 		bzero(vap, sizeof(*vap));
1328 		vap->va_type = vnode_vtype(vp);
1329 	}
1330 	return err;
1331 }
1332 
1333 /*
1334     struct vnop_inactive_args {
1335 	struct vnode *a_vp;
1336     };
1337 */
1338 static int
1339 fuse_vnop_inactive(struct vop_inactive_args *ap)
1340 {
1341 	struct vnode *vp = ap->a_vp;
1342 	struct thread *td = curthread;
1343 
1344 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
1345 	struct fuse_filehandle *fufh, *fufh_tmp;
1346 
1347 	int need_flush = 1;
1348 
1349 	ASSERT_CACHED_ATTRS_LOCKED(vp);	/* For fvdat->flag */
1350 	LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
1351 		if (need_flush && vp->v_type == VREG) {
1352 			if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
1353 				fuse_vnode_savesize(vp, NULL, 0);
1354 			}
1355 			if ((fvdat->flag & FN_REVOKED) != 0)
1356 				fuse_io_invalbuf(vp, td);
1357 			else
1358 				fuse_io_flushbuf(vp, MNT_WAIT, td);
1359 			need_flush = 0;
1360 		}
1361 		fuse_filehandle_close(vp, fufh, td, NULL);
1362 	}
1363 
1364 	if ((fvdat->flag & FN_REVOKED) != 0)
1365 		vrecycle(vp);
1366 
1367 	return 0;
1368 }
1369 
1370 /*
1371     struct vnop_ioctl_args {
1372 	struct vnode *a_vp;
1373 	u_long a_command;
1374 	caddr_t a_data;
1375 	int a_fflag;
1376 	struct ucred *a_cred;
1377 	struct thread *a_td;
1378     };
1379 */
1380 static int
1381 fuse_vnop_ioctl(struct vop_ioctl_args *ap)
1382 {
1383 	struct vnode *vp = ap->a_vp;
1384 	struct mount *mp = vnode_mount(vp);
1385 	struct ucred *cred = ap->a_cred;
1386 	struct thread *td = ap->a_td;
1387 	int err;
1388 
1389 	if (fuse_isdeadfs(vp)) {
1390 		return (ENXIO);
1391 	}
1392 
1393 	switch (ap->a_command) {
1394 	case FIOSEEKDATA:
1395 	case FIOSEEKHOLE:
1396 		/* Call FUSE_LSEEK, if we can, or fall back to vop_stdioctl */
1397 		if (fsess_maybe_impl(mp, FUSE_LSEEK)) {
1398 			off_t *offp = ap->a_data;
1399 			pid_t pid = td->td_proc->p_pid;
1400 			int whence;
1401 
1402 			if (ap->a_command == FIOSEEKDATA)
1403 				whence = SEEK_DATA;
1404 			else
1405 				whence = SEEK_HOLE;
1406 
1407 			vn_lock(vp, LK_SHARED | LK_RETRY);
1408 			err = fuse_vnop_do_lseek(vp, td, cred, pid, offp,
1409 			    whence);
1410 			VOP_UNLOCK(vp);
1411 		}
1412 		if (fsess_not_impl(mp, FUSE_LSEEK))
1413 			err = vop_stdioctl(ap);
1414 		break;
1415 	default:
1416 		err = fuse_vnop_do_ioctl(vp, ap->a_command, ap->a_data,
1417 		    ap->a_fflag, cred, td);
1418 		break;
1419 	}
1420 	return (err);
1421 }
1422 
1423 
1424 /*
1425     struct vnop_link_args {
1426 	struct vnode *a_tdvp;
1427 	struct vnode *a_vp;
1428 	struct componentname *a_cnp;
1429     };
1430 */
1431 static int
1432 fuse_vnop_link(struct vop_link_args *ap)
1433 {
1434 	struct vnode *vp = ap->a_vp;
1435 	struct vnode *tdvp = ap->a_tdvp;
1436 	struct componentname *cnp = ap->a_cnp;
1437 
1438 	struct vattr *vap = VTOVA(vp);
1439 
1440 	struct fuse_dispatcher fdi;
1441 	struct fuse_entry_out *feo;
1442 	struct fuse_link_in fli;
1443 
1444 	int err;
1445 
1446 	if (fuse_isdeadfs(vp)) {
1447 		return (EXTERROR(ENXIO, "This FUSE session is about "
1448 		    "to be closed"));
1449 	}
1450 	if (vnode_mount(tdvp) != vnode_mount(vp)) {
1451 		return (EXDEV);
1452 	}
1453 
1454 	/*
1455 	 * This is a seatbelt check to protect naive userspace filesystems from
1456 	 * themselves and the limitations of the FUSE IPC protocol.  If a
1457 	 * filesystem does not allow attribute caching, assume it is capable of
1458 	 * validating that nlink does not overflow.
1459 	 */
1460 	if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX)
1461 		return (EMLINK);
1462 	fli.oldnodeid = VTOI(vp);
1463 
1464 	fdisp_init(&fdi, 0);
1465 	fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp,
1466 	    FUSE_LINK, &fli, sizeof(fli), &fdi);
1467 	if ((err = fdisp_wait_answ(&fdi))) {
1468 		goto out;
1469 	}
1470 	feo = fdi.answ;
1471 
1472 	if (fli.oldnodeid != feo->nodeid) {
1473 		static const char exterr[] = "Server assigned wrong inode "
1474 		    "for a hard link.";
1475 		struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
1476 		fuse_warn(data, FSESS_WARN_ILLEGAL_INODE, exterr);
1477 		fuse_vnode_clear_attr_cache(vp);
1478 		fuse_vnode_clear_attr_cache(tdvp);
1479 		err = EXTERROR(EIO, exterr);
1480 		goto out;
1481 	}
1482 
1483 	err = fuse_internal_checkentry(feo, vnode_vtype(vp));
1484 	if (!err) {
1485 		/*
1486 		 * Purge the parent's attribute cache because the daemon
1487 		 * should've updated its mtime and ctime
1488 		 */
1489 		fuse_vnode_clear_attr_cache(tdvp);
1490 		fuse_internal_cache_attrs(vp, &feo->attr, feo->attr_valid,
1491 			feo->attr_valid_nsec, NULL, true);
1492 	}
1493 out:
1494 	fdisp_destroy(&fdi);
1495 	return err;
1496 }
1497 
1498 struct fuse_lookup_alloc_arg {
1499 	struct fuse_entry_out *feo;
1500 	struct componentname *cnp;
1501 	uint64_t nid;
1502 	__enum_uint8(vtype) vtyp;
1503 };
1504 
1505 /* Callback for vn_get_ino */
1506 static int
1507 fuse_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp)
1508 {
1509 	struct fuse_lookup_alloc_arg *flaa = arg;
1510 
1511 	return fuse_vnode_get(mp, flaa->feo, flaa->nid, NULL, vpp, flaa->cnp,
1512 		flaa->vtyp);
1513 }
1514 
1515 SDT_PROBE_DEFINE3(fusefs, , vnops, cache_lookup,
1516 	"int", "struct timespec*", "struct timespec*");
1517 /*
1518     struct vnop_lookup_args {
1519 	struct vnodeop_desc *a_desc;
1520 	struct vnode *a_dvp;
1521 	struct vnode **a_vpp;
1522 	struct componentname *a_cnp;
1523     };
1524 */
1525 int
1526 fuse_vnop_lookup(struct vop_lookup_args *ap)
1527 {
1528 	struct vnode *dvp = ap->a_dvp;
1529 	struct vnode **vpp = ap->a_vpp;
1530 	struct componentname *cnp = ap->a_cnp;
1531 	struct thread *td = curthread;
1532 	struct ucred *cred = cnp->cn_cred;
1533 	struct timespec now;
1534 
1535 	int nameiop = cnp->cn_nameiop;
1536 	bool isdotdot = cnp->cn_flags & ISDOTDOT;
1537 	bool islastcn = cnp->cn_flags & ISLASTCN;
1538 	struct mount *mp = vnode_mount(dvp);
1539 	struct fuse_data *data = fuse_get_mpdata(mp);
1540 	int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS;
1541 	bool is_dot;
1542 
1543 	int err = 0;
1544 	int lookup_err = 0;
1545 	struct vnode *vp = NULL;
1546 
1547 	struct fuse_dispatcher fdi;
1548 	bool did_lookup = false;
1549 	struct fuse_entry_out *feo = NULL;
1550 	__enum_uint8(vtype) vtyp;	/* vnode type of target */
1551 
1552 	uint64_t nid;
1553 
1554 	if (fuse_isdeadfs(dvp)) {
1555 		*vpp = NULL;
1556 		return (EXTERROR(ENXIO, "This FUSE session is about "
1557 		    "to be closed"));
1558 	}
1559 	if (!vnode_isdir(dvp))
1560 		return ENOTDIR;
1561 
1562 	if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP))
1563 		return EROFS;
1564 
1565 	if ((cnp->cn_flags & NOEXECCHECK) != 0)
1566 		cnp->cn_flags &= ~NOEXECCHECK;
1567 	else if ((err = fuse_internal_access(dvp, VEXEC, td, cred)))
1568 		return err;
1569 
1570 	ASSERT_CACHED_ATTRS_LOCKED(dvp);	/* For flag */
1571 	is_dot = cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.';
1572 	if (isdotdot && !(data->dataflags & FSESS_EXPORT_SUPPORT)) {
1573 		if (!(VTOFUD(dvp)->flag & FN_PARENT_NID)) {
1574 			/*
1575 			 * Since the file system doesn't support ".." lookups,
1576 			 * we have no way to find this entry.
1577 			 */
1578 			return (EXTERROR(ESTALE, "This server does not support "
1579 			    "'..' lookups"));
1580 		}
1581 		nid = VTOFUD(dvp)->parent_nid;
1582 		if (nid == 0)
1583 			return ENOENT;
1584 		/* .. is obviously a directory */
1585 		vtyp = VDIR;
1586 	} else if (is_dot) {
1587 		nid = VTOI(dvp);
1588 		/* . is obviously a directory */
1589 		vtyp = VDIR;
1590 	} else {
1591 		struct timespec timeout;
1592 		int ncpticks; /* here to accommodate for API contract */
1593 
1594 		err = cache_lookup(dvp, vpp, cnp, &timeout, &ncpticks);
1595 		getnanouptime(&now);
1596 		SDT_PROBE3(fusefs, , vnops, cache_lookup, err, &timeout, &now);
1597 		switch (err) {
1598 		case -1:		/* positive match */
1599 			if (timespeccmp(&timeout, &now, >)) {
1600 				counter_u64_add(fuse_lookup_cache_hits, 1);
1601 			} else {
1602 				/* Cache timeout */
1603 				counter_u64_add(fuse_lookup_cache_misses, 1);
1604 				bintime_clear(
1605 					&VTOFUD(*vpp)->entry_cache_timeout);
1606 				cache_purge(*vpp);
1607 				if (dvp != *vpp)
1608 					vput(*vpp);
1609 				else
1610 					vrele(*vpp);
1611 				*vpp = NULL;
1612 				break;
1613 			}
1614 			return 0;
1615 
1616 		case 0:		/* no match in cache */
1617 			counter_u64_add(fuse_lookup_cache_misses, 1);
1618 			break;
1619 
1620 		case ENOENT:		/* negative match */
1621 			if (timespeccmp(&timeout, &now, <=)) {
1622 				/* Cache timeout */
1623 				cache_purge_negative(dvp);
1624 				break;
1625 			}
1626 			/* fall through */
1627 		default:
1628 			return err;
1629 		}
1630 
1631 		fdisp_init(&fdi, cnp->cn_namelen + 1);
1632 		fdisp_make(&fdi, FUSE_LOOKUP, mp, VTOI(dvp), td, cred);
1633 
1634 		memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1635 		((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1636 		lookup_err = fdisp_wait_answ(&fdi);
1637 		did_lookup = true;
1638 
1639 		if (!lookup_err) {
1640 			/* lookup call succeeded */
1641 			feo = (struct fuse_entry_out *)fdi.answ;
1642 			nid = feo->nodeid;
1643 			if (nid == 0) {
1644 				/* zero nodeid means ENOENT and cache it */
1645 				struct timespec timeout;
1646 
1647 				fdi.answ_stat = ENOENT;
1648 				lookup_err = ENOENT;
1649 				if (cnp->cn_flags & MAKEENTRY) {
1650 					fuse_validity_2_timespec(feo, &timeout);
1651 					/* Use the same entry_time for .. as for
1652 					 * the file itself.  That doesn't honor
1653 					 * exactly what the fuse server tells
1654 					 * us, but to do otherwise would require
1655 					 * another cache lookup at this point.
1656 					 */
1657 					struct timespec *dtsp = NULL;
1658 					cache_enter_time(dvp, *vpp, cnp,
1659 						&timeout, dtsp);
1660 				}
1661 			}
1662 			vtyp = IFTOVT(feo->attr.mode);
1663 		}
1664 		if (lookup_err && (!fdi.answ_stat || lookup_err != ENOENT)) {
1665 			fdisp_destroy(&fdi);
1666 			return lookup_err;
1667 		}
1668 	}
1669 	/* lookup_err, if non-zero, must be ENOENT at this point */
1670 
1671 	if (lookup_err) {
1672 		/* Entry not found */
1673 		if ((nameiop == CREATE || nameiop == RENAME) && islastcn) {
1674 			if (default_permissions)
1675 				err = fuse_internal_access(dvp, VWRITE, td,
1676 				    cred);
1677 			else
1678 				err = 0;
1679 			if (!err) {
1680 				err = EJUSTRETURN;
1681 			}
1682 		} else {
1683 			err = ENOENT;
1684 		}
1685 	} else {
1686 		/* Entry was found */
1687 		if (isdotdot) {
1688 			struct fuse_lookup_alloc_arg flaa;
1689 
1690 			flaa.nid = nid;
1691 			flaa.feo = feo;
1692 			flaa.cnp = cnp;
1693 			flaa.vtyp = vtyp;
1694 			err = vn_vget_ino_gen(dvp, fuse_lookup_alloc, &flaa, 0,
1695 				&vp);
1696 			*vpp = vp;
1697 		} else if (nid == VTOI(dvp)) {
1698 			if (is_dot) {
1699 				vref(dvp);
1700 				*vpp = dvp;
1701 			} else {
1702 				static const char exterr[] = "Server assigned "
1703 				    "same inode to both parent and child.";
1704 				fuse_warn(fuse_get_mpdata(mp),
1705 				    FSESS_WARN_ILLEGAL_INODE, exterr);
1706 				err = EXTERROR(EIO, exterr);
1707 			}
1708 
1709 		} else {
1710 			struct fuse_vnode_data *fvdat;
1711 
1712 			err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
1713 			    &vp, cnp, vtyp);
1714 			if (err)
1715 				goto out;
1716 			*vpp = vp;
1717 			fvdat = VTOFUD(vp);
1718 
1719 			MPASS(feo != NULL);
1720 			if (timespeccmp(&now, &fvdat->last_local_modify, >)) {
1721 				/*
1722 				 * Attributes from the server are definitely
1723 				 * newer than the last attributes we sent to
1724 				 * the server, so cache them.
1725 				 */
1726 				fuse_internal_cache_attrs(*vpp, &feo->attr,
1727 					feo->attr_valid, feo->attr_valid_nsec,
1728 					NULL, true);
1729 			}
1730 			fuse_validity_2_bintime(feo->entry_valid,
1731 				feo->entry_valid_nsec,
1732 				&fvdat->entry_cache_timeout);
1733 
1734 			if ((nameiop == DELETE || nameiop == RENAME) &&
1735 				islastcn && default_permissions)
1736 			{
1737 				struct vattr dvattr;
1738 
1739 				err = fuse_internal_access(dvp, VWRITE, td,
1740 					cred);
1741 				if (err != 0)
1742 					goto out;
1743 				/*
1744 				 * if the parent's sticky bit is set, check
1745 				 * whether we're allowed to remove the file.
1746 				 * Need to figure out the vnode locking to make
1747 				 * this work.
1748 				 */
1749 				err = fuse_internal_getattr(dvp, &dvattr, cred,
1750 						td);
1751 				if (err == 0 &&
1752 					(dvattr.va_mode & S_ISTXT) &&
1753 					fuse_internal_access(dvp, VADMIN, td,
1754 						cred) &&
1755 					fuse_internal_access(*vpp, VADMIN, td,
1756 						cred))
1757 				{
1758 					err = EPERM;
1759 				}
1760 			}
1761 		}
1762 	}
1763 out:
1764 	if (err) {
1765 		if (vp != NULL && dvp != vp)
1766 			vput(vp);
1767 		else if (vp != NULL)
1768 			vrele(vp);
1769 		*vpp = NULL;
1770 	}
1771 	if (did_lookup)
1772 		fdisp_destroy(&fdi);
1773 
1774 	return err;
1775 }
1776 
1777 /*
1778     struct vnop_mkdir_args {
1779 	struct vnode *a_dvp;
1780 	struct vnode **a_vpp;
1781 	struct componentname *a_cnp;
1782 	struct vattr *a_vap;
1783     };
1784 */
1785 static int
1786 fuse_vnop_mkdir(struct vop_mkdir_args *ap)
1787 {
1788 	struct vnode *dvp = ap->a_dvp;
1789 	struct vnode **vpp = ap->a_vpp;
1790 	struct componentname *cnp = ap->a_cnp;
1791 	struct vattr *vap = ap->a_vap;
1792 
1793 	struct fuse_mkdir_in fmdi;
1794 
1795 	if (fuse_isdeadfs(dvp)) {
1796 		return (EXTERROR(ENXIO, "This FUSE session is about "
1797 		    "to be closed"));
1798 	}
1799 	fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
1800 	fmdi.umask = curthread->td_proc->p_pd->pd_cmask;
1801 
1802 	return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
1803 	    sizeof(fmdi), VDIR));
1804 }
1805 
1806 /*
1807     struct vnop_mknod_args {
1808 	struct vnode *a_dvp;
1809 	struct vnode **a_vpp;
1810 	struct componentname *a_cnp;
1811 	struct vattr *a_vap;
1812     };
1813 */
1814 static int
1815 fuse_vnop_mknod(struct vop_mknod_args *ap)
1816 {
1817 
1818 	struct vnode *dvp = ap->a_dvp;
1819 	struct vnode **vpp = ap->a_vpp;
1820 	struct componentname *cnp = ap->a_cnp;
1821 	struct vattr *vap = ap->a_vap;
1822 
1823 	if (fuse_isdeadfs(dvp))
1824 		return (EXTERROR(ENXIO, "This FUSE session is about "
1825 		    "to be closed"));
1826 
1827 	return fuse_internal_mknod(dvp, vpp, cnp, vap);
1828 }
1829 
1830 /*
1831     struct vop_open_args {
1832 	struct vnode *a_vp;
1833 	int  a_mode;
1834 	struct ucred *a_cred;
1835 	struct thread *a_td;
1836 	int a_fdidx; / struct file *a_fp;
1837     };
1838 */
1839 static int
1840 fuse_vnop_open(struct vop_open_args *ap)
1841 {
1842 	struct vnode *vp = ap->a_vp;
1843 	int a_mode = ap->a_mode;
1844 	struct thread *td = ap->a_td;
1845 	struct ucred *cred = ap->a_cred;
1846 	pid_t pid = td->td_proc->p_pid;
1847 
1848 	if (fuse_isdeadfs(vp))
1849 		return (EXTERROR(ENXIO, "This FUSE session is about "
1850 		    "to be closed"));
1851 	if (VN_ISDEV(vp) || vp->v_type == VFIFO)
1852 		return (EXTERROR(EOPNOTSUPP, "Unsupported vnode type",
1853 		    vp->v_type));
1854 	if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0)
1855 		return (EXTERROR(EINVAL, "Illegal mode", a_mode));
1856 
1857 	if (fuse_filehandle_validrw(vp, a_mode, cred, pid)) {
1858 		fuse_vnode_open(vp, 0, td);
1859 		return 0;
1860 	}
1861 
1862 	return fuse_filehandle_open(vp, a_mode, NULL, td, cred);
1863 }
1864 
1865 static int
1866 fuse_vnop_pathconf(struct vop_pathconf_args *ap)
1867 {
1868 	struct vnode *vp = ap->a_vp;
1869 	struct mount *mp;
1870 	struct fuse_filehandle *fufh;
1871 	int err;
1872 	bool closefufh = false;
1873 
1874 	switch (ap->a_name) {
1875 	case _PC_FILESIZEBITS:
1876 		*ap->a_retval = 64;
1877 		return (0);
1878 	case _PC_NAME_MAX:
1879 		*ap->a_retval = NAME_MAX;
1880 		return (0);
1881 	case _PC_LINK_MAX:
1882 		*ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX);
1883 		return (0);
1884 	case _PC_SYMLINK_MAX:
1885 		*ap->a_retval = MAXPATHLEN;
1886 		return (0);
1887 	case _PC_NO_TRUNC:
1888 		*ap->a_retval = 1;
1889 		return (0);
1890 	case _PC_MIN_HOLE_SIZE:
1891 		/*
1892 		 * The FUSE protocol provides no mechanism for a server to
1893 		 * report _PC_MIN_HOLE_SIZE.  It's a protocol bug.  Instead,
1894 		 * return EINVAL if the server does not support FUSE_LSEEK, or
1895 		 * 1 if it does.
1896 		 */
1897 		mp = vnode_mount(vp);
1898 		if (!fsess_is_impl(mp, FUSE_LSEEK) &&
1899 		    !fsess_not_impl(mp, FUSE_LSEEK)) {
1900 			off_t offset = 0;
1901 
1902 			/*
1903 			 * Issue a FUSE_LSEEK to find out if it's supported.
1904 			 * Use SEEK_DATA instead of SEEK_HOLE, because the
1905 			 * latter generally requires sequential scans of file
1906 			 * metadata, which can be slow.
1907 			 */
1908 			err = fuse_vnop_do_lseek(vp, curthread,
1909 			    curthread->td_ucred, curthread->td_proc->p_pid,
1910 			    &offset, SEEK_DATA);
1911 			if (err == EBADF) {
1912 				/*
1913 				 * pathconf() doesn't necessarily open the
1914 				 * file.  So we may need to do it here.
1915 				 */
1916 				err = fuse_filehandle_open(vp, FREAD, &fufh,
1917 				    curthread, curthread->td_ucred);
1918 				if (err == 0) {
1919 					closefufh = true;
1920 					err = fuse_vnop_do_lseek(vp, curthread,
1921 					    curthread->td_ucred,
1922 					    curthread->td_proc->p_pid, &offset,
1923 					    SEEK_DATA);
1924 				}
1925 				if (closefufh)
1926 					fuse_filehandle_close(vp, fufh,
1927 					    curthread, curthread->td_ucred);
1928 			}
1929 
1930 		}
1931 
1932 		if (fsess_is_impl(mp, FUSE_LSEEK)) {
1933 			*ap->a_retval = 1;
1934 			return (0);
1935 		} else if (fsess_not_impl(mp, FUSE_LSEEK)) {
1936 			/* FUSE_LSEEK is not implemented */
1937 			return (EXTERROR(EINVAL, "This server does not "
1938 			    "implement FUSE_LSEEK"));
1939 		} else {
1940 			return (err);
1941 		}
1942 	default:
1943 		return (vop_stdpathconf(ap));
1944 	}
1945 }
1946 
1947 SDT_PROBE_DEFINE3(fusefs, , vnops, filehandles_closed, "struct vnode*",
1948     "struct uio*", "struct ucred*");
1949 /*
1950     struct vnop_read_args {
1951 	struct vnode *a_vp;
1952 	struct uio *a_uio;
1953 	int  a_ioflag;
1954 	struct ucred *a_cred;
1955     };
1956 */
1957 static int
1958 fuse_vnop_read(struct vop_read_args *ap)
1959 {
1960 	struct vnode *vp = ap->a_vp;
1961 	struct uio *uio = ap->a_uio;
1962 	int ioflag = ap->a_ioflag;
1963 	struct ucred *cred = ap->a_cred;
1964 	pid_t pid = curthread->td_proc->p_pid;
1965 	struct fuse_filehandle *fufh;
1966 	int err;
1967 	bool closefufh = false, directio;
1968 
1969 	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
1970 
1971 	if (fuse_isdeadfs(vp)) {
1972 		return (EXTERROR(ENXIO, "This FUSE session is about "
1973 		    "to be closed"));
1974 	}
1975 
1976 	/*
1977 	 * XXX Check this flag without the lock.  See
1978 	 * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=293088
1979 	 */
1980 	if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1981 		ioflag |= IO_DIRECT;
1982 	}
1983 
1984 	err = fuse_filehandle_getrw(vp, FREAD, &fufh, cred, pid);
1985 	if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
1986 		/*
1987 		 * nfsd will do I/O without first doing VOP_OPEN.  We
1988 		 * must implicitly open the file here
1989 		 */
1990 		err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
1991 		closefufh = true;
1992 	}
1993 	if (err) {
1994 		SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
1995 		return err;
1996 	}
1997 
1998 	/*
1999          * Ideally, when the daemon asks for direct io at open time, the
2000          * standard file flag should be set according to this, so that would
2001          * just change the default mode, which later on could be changed via
2002          * fcntl(2).
2003          * But this doesn't work, the O_DIRECT flag gets cleared at some point
2004          * (don't know where). So to make any use of the Fuse direct_io option,
2005          * we hardwire it into the file's private data (similarly to Linux,
2006          * btw.).
2007          */
2008 	directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
2009 
2010 	fuse_vnode_update(vp, FN_ATIMECHANGE);
2011 	if (directio) {
2012 		SDT_PROBE2(fusefs, , vnops, trace, 1, "direct read of vnode");
2013 		err = fuse_read_directbackend(vp, uio, cred, fufh);
2014 	} else {
2015 		SDT_PROBE2(fusefs, , vnops, trace, 1, "buffered read of vnode");
2016 		err = fuse_read_biobackend(vp, uio, ioflag, cred, fufh, pid);
2017 	}
2018 
2019 	if (closefufh)
2020 		fuse_filehandle_close(vp, fufh, curthread, cred);
2021 
2022 	return (err);
2023 }
2024 
2025 /*
2026     struct vnop_readdir_args {
2027 	struct vnode *a_vp;
2028 	struct uio *a_uio;
2029 	struct ucred *a_cred;
2030 	int *a_eofflag;
2031 	int *a_ncookies;
2032 	uint64_t **a_cookies;
2033     };
2034 */
2035 static int
2036 fuse_vnop_readdir(struct vop_readdir_args *ap)
2037 {
2038 	struct vnode *vp = ap->a_vp;
2039 	struct uio *uio = ap->a_uio;
2040 	struct ucred *cred = ap->a_cred;
2041 	struct fuse_filehandle *fufh = NULL;
2042 	struct mount *mp = vnode_mount(vp);
2043 	struct fuse_iov cookediov;
2044 	int err = 0;
2045 	uint64_t *cookies;
2046 	ssize_t tresid;
2047 	int ncookies;
2048 	bool closefufh = false;
2049 	pid_t pid = curthread->td_proc->p_pid;
2050 
2051 	if (ap->a_eofflag)
2052 		*ap->a_eofflag = 0;
2053 	if (fuse_isdeadfs(vp)) {
2054 		return (EXTERROR(ENXIO, "This FUSE session is about "
2055 		    "to be closed"));
2056 	}
2057 	if (uio_resid(uio) < sizeof(struct dirent))
2058 		return (EXTERROR(EINVAL, "Buffer is too small"));
2059 
2060 	tresid = uio->uio_resid;
2061 	err = fuse_filehandle_get(vp, FREAD, &fufh, cred, pid);
2062 	if (err == EBADF && mp->mnt_flag & MNT_EXPORTED) {
2063 		KASSERT(!fsess_is_impl(mp, FUSE_OPENDIR),
2064 			("FUSE file systems that implement "
2065 			 "FUSE_OPENDIR should not be exported"));
2066 		/*
2067 		 * nfsd will do VOP_READDIR without first doing VOP_OPEN.  We
2068 		 * must implicitly open the directory here.
2069 		 */
2070 		err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
2071 		closefufh = true;
2072 	}
2073 	if (err)
2074 		return (err);
2075 	if (ap->a_ncookies != NULL) {
2076 		ncookies = uio->uio_resid /
2077 			(offsetof(struct dirent, d_name) + 4) + 1;
2078 		cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
2079 		*ap->a_ncookies = ncookies;
2080 		*ap->a_cookies = cookies;
2081 	} else {
2082 		ncookies = 0;
2083 		cookies = NULL;
2084 	}
2085 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
2086 	fiov_init(&cookediov, DIRCOOKEDSIZE);
2087 
2088 	err = fuse_internal_readdir(vp, uio, fufh, &cookediov,
2089 		&ncookies, cookies);
2090 
2091 	fiov_teardown(&cookediov);
2092 	if (closefufh)
2093 		fuse_filehandle_close(vp, fufh, curthread, cred);
2094 
2095 	if (ap->a_ncookies != NULL) {
2096 		if (err == 0) {
2097 			*ap->a_ncookies -= ncookies;
2098 		} else {
2099 			free(*ap->a_cookies, M_TEMP);
2100 			*ap->a_ncookies = 0;
2101 			*ap->a_cookies = NULL;
2102 		}
2103 	}
2104 	if (err == 0 && tresid == uio->uio_resid)
2105 		*ap->a_eofflag = 1;
2106 
2107 	return err;
2108 }
2109 
2110 /*
2111     struct vnop_readlink_args {
2112 	struct vnode *a_vp;
2113 	struct uio *a_uio;
2114 	struct ucred *a_cred;
2115     };
2116 */
2117 static int
2118 fuse_vnop_readlink(struct vop_readlink_args *ap)
2119 {
2120 	struct vnode *vp = ap->a_vp;
2121 	struct uio *uio = ap->a_uio;
2122 	struct ucred *cred = ap->a_cred;
2123 
2124 	struct fuse_dispatcher fdi;
2125 	int err;
2126 
2127 	if (fuse_isdeadfs(vp)) {
2128 		return (EXTERROR(ENXIO, "This FUSE session is about "
2129 		    "to be closed"));
2130 	}
2131 	if (!vnode_islnk(vp)) {
2132 		return EINVAL;
2133 	}
2134 	fdisp_init(&fdi, 0);
2135 	err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred);
2136 	if (err) {
2137 		goto out;
2138 	}
2139 	if (strnlen(fdi.answ, fdi.iosize) + 1 < fdi.iosize) {
2140 		static const char exterr[] = "Server returned an embedded NUL "
2141 		    "from FUSE_READLINK.";
2142 		struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
2143 		fuse_warn(data, FSESS_WARN_READLINK_EMBEDDED_NUL, exterr);
2144 		err = EXTERROR(EIO, exterr);
2145 		goto out;
2146 	}
2147 	if (((char *)fdi.answ)[0] == '/' &&
2148 	    fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) {
2149 		char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname;
2150 
2151 		err = uiomove(mpth, strlen(mpth), uio);
2152 	}
2153 	if (!err) {
2154 		err = uiomove(fdi.answ, fdi.iosize, uio);
2155 	}
2156 out:
2157 	fdisp_destroy(&fdi);
2158 	return err;
2159 }
2160 
2161 /*
2162     struct vnop_reclaim_args {
2163 	struct vnode *a_vp;
2164     };
2165 */
2166 static int
2167 fuse_vnop_reclaim(struct vop_reclaim_args *ap)
2168 {
2169 	struct vnode *vp = ap->a_vp;
2170 	struct thread *td = curthread;
2171 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
2172 	struct fuse_filehandle *fufh, *fufh_tmp;
2173 
2174 	if (!fvdat) {
2175 		panic("FUSE: no vnode data during recycling");
2176 	}
2177 	LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
2178 		printf("FUSE: vnode being reclaimed with open fufh "
2179 			"(type=%#x)", fufh->fufh_type);
2180 		fuse_filehandle_close(vp, fufh, td, NULL);
2181 	}
2182 
2183 	if (VTOI(vp) == 1) {
2184 		/*
2185 		 * Don't send FUSE_FORGET for the root inode, because
2186 		 * we never send FUSE_LOOKUP for it (see
2187 		 * fuse_vfsop_root) and we don't want the server to see
2188 		 * mismatched lookup counts.
2189 		 */
2190 		struct fuse_data *data;
2191 		struct vnode *vroot;
2192 
2193 		data = fuse_get_mpdata(vnode_mount(vp));
2194 		FUSE_LOCK();
2195 		vroot = data->vroot;
2196 		data->vroot = NULL;
2197 		FUSE_UNLOCK();
2198 		if (vroot)
2199 			vrele(vroot);
2200 	} else if (!fuse_isdeadfs(vp) && fvdat->nlookup > 0) {
2201 		fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
2202 		    fvdat->nlookup);
2203 	}
2204 	cache_purge(vp);
2205 	vfs_hash_remove(vp);
2206 	fuse_vnode_destroy(vp);
2207 
2208 	return 0;
2209 }
2210 
2211 /*
2212     struct vnop_remove_args {
2213 	struct vnode *a_dvp;
2214 	struct vnode *a_vp;
2215 	struct componentname *a_cnp;
2216     };
2217 */
2218 static int
2219 fuse_vnop_remove(struct vop_remove_args *ap)
2220 {
2221 	struct vnode *dvp = ap->a_dvp;
2222 	struct vnode *vp = ap->a_vp;
2223 	struct componentname *cnp = ap->a_cnp;
2224 
2225 	int err;
2226 
2227 	if (fuse_isdeadfs(vp)) {
2228 		return (EXTERROR(ENXIO, "This FUSE session is about "
2229 		    "to be closed"));
2230 	}
2231 	if (vnode_isdir(vp)) {
2232 		return (EXTERROR(EPERM, "vnode is a directory"));
2233 	}
2234 
2235 	err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
2236 
2237 	return err;
2238 }
2239 
2240 SDT_PROBE_DEFINE4(fusefs, , vnops, erelookup, "struct vnode*",
2241 	"struct vnode*", "struct vnode*", "struct vnode*");
2242 /*
2243     struct vnop_rename_args {
2244 	struct vnode *a_fdvp;
2245 	struct vnode *a_fvp;
2246 	struct componentname *a_fcnp;
2247 	struct vnode *a_tdvp;
2248 	struct vnode *a_tvp;
2249 	struct componentname *a_tcnp;
2250     };
2251 */
2252 static int
2253 fuse_vnop_rename(struct vop_rename_args *ap)
2254 {
2255 	struct vnode *fdvp = ap->a_fdvp;
2256 	struct vnode *fvp = ap->a_fvp;
2257 	struct componentname *fcnp = ap->a_fcnp;
2258 	struct vnode *tdvp = ap->a_tdvp;
2259 	struct vnode *tvp = ap->a_tvp;
2260 	struct componentname *tcnp = ap->a_tcnp;
2261 	struct fuse_data *data;
2262 	bool newparent = fdvp != tdvp;
2263 	bool isdir = fvp->v_type == VDIR;
2264 	int locktype;
2265 	int err = 0;
2266 
2267 	if (fuse_isdeadfs(fdvp)) {
2268 		return (EXTERROR(ENXIO, "This FUSE session is about "
2269 		    "to be closed"));
2270 	}
2271 	if (fvp->v_mount != tdvp->v_mount ||
2272 	    (tvp && fvp->v_mount != tvp->v_mount)) {
2273 		SDT_PROBE2(fusefs, , vnops, trace, 1, "cross-device rename");
2274 		err = EXTERROR(EXDEV, "Cross-device rename");
2275 		goto out;
2276 	}
2277 	if (ap->a_flags != 0) {
2278 		err = EOPNOTSUPP;
2279 		goto out;
2280 	}
2281 	cache_purge(fvp);
2282 
2283 	/*
2284 	 * FUSE library is expected to check if target directory is not
2285 	 * under the source directory in the file system tree.
2286 	 * Linux performs this check at VFS level.
2287 	 */
2288 	/*
2289 	 * If source is a directory, and it will get a new parent, user must
2290 	 * have write permission to it, so ".." can be modified.
2291 	 */
2292 	data = fuse_get_mpdata(vnode_mount(tdvp));
2293 
2294 	if (tdvp != fdvp)
2295 		locktype = LK_EXCLUSIVE; /* for fuse_vnode_setparent */
2296 	else
2297 		locktype = LK_SHARED;
2298 
2299 	/*
2300 	 * Must use LK_NOWAIT to prevent LORs between fvp and tdvp or
2301 	 * tvp
2302 	 */
2303 	if (vn_lock(fvp, locktype | LK_NOWAIT) != 0) {
2304 		/*
2305 		 * Can't release tdvp or tvp to try avoiding the LOR.
2306 		 * Must return instead.
2307 		 */
2308 		SDT_PROBE4(fusefs, , vnops, erelookup, fdvp, fvp, tdvp,
2309 			tvp);
2310 		err = ERELOOKUP;
2311 		goto out;
2312 	}
2313 
2314 	if (data->dataflags & FSESS_DEFAULT_PERMISSIONS && isdir && newparent) {
2315 		err = fuse_internal_access(fvp, VWRITE,
2316 			curthread, tcnp->cn_cred);
2317 		if (err)
2318 			goto unlock;
2319 	}
2320 	err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp);
2321 	if (err == 0) {
2322 		if (tdvp != fdvp)
2323 			fuse_vnode_setparent(fvp, tdvp);
2324 		if (tvp != NULL)
2325 			fuse_vnode_setparent(tvp, NULL);
2326 	}
2327 
2328 	if (tvp != NULL && tvp != fvp) {
2329 		cache_purge(tvp);
2330 	}
2331 	if (vnode_isdir(fvp)) {
2332 		if (((tvp != NULL) && vnode_isdir(tvp)) || vnode_isdir(fvp)) {
2333 			cache_purge(tdvp);
2334 		}
2335 		cache_purge(fdvp);
2336 	}
2337 unlock:
2338 	VOP_UNLOCK(fvp);
2339 out:
2340 	if (tdvp == tvp) {
2341 		vrele(tdvp);
2342 	} else {
2343 		vput(tdvp);
2344 	}
2345 	if (tvp != NULL) {
2346 		vput(tvp);
2347 	}
2348 	vrele(fdvp);
2349 	vrele(fvp);
2350 
2351 	return err;
2352 }
2353 
2354 /*
2355     struct vnop_rmdir_args {
2356 	    struct vnode *a_dvp;
2357 	    struct vnode *a_vp;
2358 	    struct componentname *a_cnp;
2359     } *ap;
2360 */
2361 static int
2362 fuse_vnop_rmdir(struct vop_rmdir_args *ap)
2363 {
2364 	struct vnode *dvp = ap->a_dvp;
2365 	struct vnode *vp = ap->a_vp;
2366 
2367 	int err;
2368 
2369 	if (fuse_isdeadfs(vp)) {
2370 		return (EXTERROR(ENXIO, "This FUSE session is about "
2371 		    "to be closed"));
2372 	}
2373 	if (VTOFUD(vp) == VTOFUD(dvp)) {
2374 		return (EXTERROR(EINVAL, "Directory to be removed "
2375 		    "contains itself"));
2376 	}
2377 	err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
2378 
2379 	return err;
2380 }
2381 
2382 /*
2383     struct vnop_setattr_args {
2384 	struct vnode *a_vp;
2385 	struct vattr *a_vap;
2386 	struct ucred *a_cred;
2387 	struct thread *a_td;
2388     };
2389 */
2390 static int
2391 fuse_vnop_setattr(struct vop_setattr_args *ap)
2392 {
2393 	struct vnode *vp = ap->a_vp;
2394 	struct vattr *vap = ap->a_vap;
2395 	struct ucred *cred = ap->a_cred;
2396 	struct thread *td = curthread;
2397 	struct mount *mp;
2398 	struct fuse_data *data;
2399 	struct vattr old_va;
2400 	int dataflags;
2401 	int err = 0, err2;
2402 	accmode_t accmode = 0;
2403 	bool checkperm;
2404 	bool drop_suid = false;
2405 
2406 	mp = vnode_mount(vp);
2407 	data = fuse_get_mpdata(mp);
2408 	dataflags = data->dataflags;
2409 	checkperm = dataflags & FSESS_DEFAULT_PERMISSIONS;
2410 
2411 	if (fuse_isdeadfs(vp)) {
2412 		return (EXTERROR(ENXIO, "This FUSE session is about "
2413 		    "to be closed"));
2414 	}
2415 
2416 	if (vap->va_uid != (uid_t)VNOVAL) {
2417 		if (checkperm) {
2418 			/* Only root may change a file's owner */
2419 			err = priv_check_cred(cred, PRIV_VFS_CHOWN);
2420 			if (err) {
2421 				/* As a special case, allow the null chown */
2422 				err2 = fuse_internal_getattr(vp, &old_va, cred,
2423 					td);
2424 				if (err2)
2425 					return (err2);
2426 				if (vap->va_uid != old_va.va_uid)
2427 					return err;
2428 				drop_suid = true;
2429 			}
2430 		}
2431 		accmode |= VADMIN;
2432 	}
2433 	if (vap->va_gid != (gid_t)VNOVAL) {
2434 		if (checkperm && priv_check_cred(cred, PRIV_VFS_CHOWN))
2435 			drop_suid = true;
2436 		if (checkperm && !groupmember(vap->va_gid, cred)) {
2437 			/*
2438 			 * Non-root users may only chgrp to one of their own
2439 			 * groups
2440 			 */
2441 			err = priv_check_cred(cred, PRIV_VFS_CHOWN);
2442 			if (err) {
2443 				/* As a special case, allow the null chgrp */
2444 				err2 = fuse_internal_getattr(vp, &old_va, cred,
2445 					td);
2446 				if (err2)
2447 					return (err2);
2448 				if (vap->va_gid != old_va.va_gid)
2449 					return err;
2450 			}
2451 		}
2452 		accmode |= VADMIN;
2453 	}
2454 	if (vap->va_size != VNOVAL) {
2455 		switch (vp->v_type) {
2456 		case VDIR:
2457 			return (EISDIR);
2458 		case VLNK:
2459 		case VREG:
2460 			if (vfs_isrdonly(mp))
2461 				return (EROFS);
2462 			err = vn_rlimit_trunc(vap->va_size, td);
2463 			if (err)
2464 				return (err);
2465 			break;
2466 		default:
2467 			/*
2468 			 * According to POSIX, the result is unspecified
2469 			 * for file types other than regular files,
2470 			 * directories and shared memory objects.  We
2471 			 * don't support shared memory objects in the file
2472 			 * system, and have dubious support for truncating
2473 			 * symlinks.  Just ignore the request in other cases.
2474 			 */
2475 			return (0);
2476 		}
2477 		/* Don't set accmode.  Permission to trunc is checked upstack */
2478 	}
2479 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
2480 		if (vap->va_vaflags & VA_UTIMES_NULL)
2481 			accmode |= VWRITE;
2482 		else
2483 			accmode |= VADMIN;
2484 	}
2485 	if (drop_suid) {
2486 		if (vap->va_mode != (mode_t)VNOVAL)
2487 			vap->va_mode &= ~(S_ISUID | S_ISGID);
2488 		else {
2489 			err = fuse_internal_getattr(vp, &old_va, cred, td);
2490 			if (err)
2491 				return (err);
2492 			vap->va_mode = old_va.va_mode & ~(S_ISUID | S_ISGID);
2493 		}
2494 	}
2495 	if (vap->va_mode != (mode_t)VNOVAL) {
2496 		/* Only root may set the sticky bit on non-directories */
2497 		if (checkperm && vp->v_type != VDIR && (vap->va_mode & S_ISTXT)
2498 		    && priv_check_cred(cred, PRIV_VFS_STICKYFILE))
2499 			return EFTYPE;
2500 		if (checkperm && (vap->va_mode & S_ISGID)) {
2501 			err = fuse_internal_getattr(vp, &old_va, cred, td);
2502 			if (err)
2503 				return (err);
2504 			if (!groupmember(old_va.va_gid, cred)) {
2505 				err = priv_check_cred(cred, PRIV_VFS_SETGID);
2506 				if (err)
2507 					return (err);
2508 			}
2509 		}
2510 		accmode |= VADMIN;
2511 	}
2512 
2513 	if (vfs_isrdonly(mp))
2514 		return EROFS;
2515 
2516 	if (checkperm) {
2517 		err = fuse_internal_access(vp, accmode, td, cred);
2518 	} else {
2519 		err = 0;
2520 	}
2521 	if (err)
2522 		return err;
2523 	else
2524 		return fuse_internal_setattr(vp, vap, td, cred);
2525 }
2526 
2527 /*
2528     struct vnop_strategy_args {
2529 	struct vnode *a_vp;
2530 	struct buf *a_bp;
2531     };
2532 */
2533 static int
2534 fuse_vnop_strategy(struct vop_strategy_args *ap)
2535 {
2536 	struct vnode *vp = ap->a_vp;
2537 	struct buf *bp = ap->a_bp;
2538 
2539 	if (!vp || fuse_isdeadfs(vp)) {
2540 		bp->b_ioflags |= BIO_ERROR;
2541 		bp->b_error = ENXIO;
2542 		bufdone(bp);
2543 		return 0;
2544 	}
2545 
2546 	/*
2547 	 * VOP_STRATEGY always returns zero and signals error via bp->b_ioflags.
2548 	 * fuse_io_strategy sets bp's error fields
2549 	 */
2550 	(void)fuse_io_strategy(vp, bp);
2551 
2552 	return 0;
2553 }
2554 
2555 /*
2556     struct vnop_symlink_args {
2557 	struct vnode *a_dvp;
2558 	struct vnode **a_vpp;
2559 	struct componentname *a_cnp;
2560 	struct vattr *a_vap;
2561 	char *a_target;
2562     };
2563 */
2564 static int
2565 fuse_vnop_symlink(struct vop_symlink_args *ap)
2566 {
2567 	struct vnode *dvp = ap->a_dvp;
2568 	struct vnode **vpp = ap->a_vpp;
2569 	struct componentname *cnp = ap->a_cnp;
2570 	const char *target = ap->a_target;
2571 
2572 	struct fuse_dispatcher fdi;
2573 
2574 	int err;
2575 	size_t len;
2576 
2577 	if (fuse_isdeadfs(dvp)) {
2578 		return (EXTERROR(ENXIO, "This FUSE session is about "
2579 		    "to be closed"));
2580 	}
2581 	/*
2582 	 * Unlike the other creator type calls, here we have to create a message
2583 	 * where the name of the new entry comes first, and the data describing
2584 	 * the entry comes second.
2585 	 * Hence we can't rely on our handy fuse_internal_newentry() routine,
2586 	 * but put together the message manually and just call the core part.
2587 	 */
2588 
2589 	len = strlen(target) + 1;
2590 	fdisp_init(&fdi, len + cnp->cn_namelen + 1);
2591 	fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
2592 
2593 	memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
2594 	((char *)fdi.indata)[cnp->cn_namelen] = '\0';
2595 	memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
2596 
2597 	err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
2598 	fdisp_destroy(&fdi);
2599 	return err;
2600 }
2601 
2602 /*
2603     struct vnop_write_args {
2604 	struct vnode *a_vp;
2605 	struct uio *a_uio;
2606 	int  a_ioflag;
2607 	struct ucred *a_cred;
2608     };
2609 */
2610 static int
2611 fuse_vnop_write(struct vop_write_args *ap)
2612 {
2613 	struct vnode *vp = ap->a_vp;
2614 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
2615 	struct uio *uio = ap->a_uio;
2616 	int ioflag = ap->a_ioflag;
2617 	struct ucred *cred = ap->a_cred;
2618 	pid_t pid = curthread->td_proc->p_pid;
2619 	struct fuse_filehandle *fufh;
2620 	int err;
2621 	bool closefufh = false, directio;
2622 
2623 	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
2624 
2625 	if (fuse_isdeadfs(vp)) {
2626 		return (EXTERROR(ENXIO, "This FUSE session is about "
2627 		    "to be closed"));
2628 	}
2629 
2630 	/*
2631 	 * XXX Check this flag without the lock.  See
2632 	 * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=293088
2633 	 */
2634 	if (fvdat->flag & FN_DIRECTIO)
2635 		ioflag |= IO_DIRECT;
2636 
2637 	err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
2638 	if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
2639 		/*
2640 		 * nfsd will do I/O without first doing VOP_OPEN.  We
2641 		 * must implicitly open the file here
2642 		 */
2643 		err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred);
2644 		closefufh = true;
2645 	}
2646 	if (err) {
2647 		SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
2648 		return err;
2649 	}
2650 
2651 	/*
2652          * Ideally, when the daemon asks for direct io at open time, the
2653          * standard file flag should be set according to this, so that would
2654          * just change the default mode, which later on could be changed via
2655          * fcntl(2).
2656          * But this doesn't work, the O_DIRECT flag gets cleared at some point
2657          * (don't know where). So to make any use of the Fuse direct_io option,
2658          * we hardwire it into the file's private data (similarly to Linux,
2659          * btw.).
2660          */
2661 	directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
2662 
2663 	fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
2664 	if (directio) {
2665 		off_t start, end, filesize;
2666 		bool pages = (ioflag & IO_VMIO) != 0;
2667 
2668 		SDT_PROBE2(fusefs, , vnops, trace, 1, "direct write of vnode");
2669 
2670 		err = fuse_vnode_size(vp, &filesize, cred, curthread);
2671 		if (err)
2672 			goto out;
2673 
2674 		start = uio->uio_offset;
2675 		end = start + uio->uio_resid;
2676 		if (!pages) {
2677 			err = fuse_inval_buf_range(vp, filesize, start,
2678 			    end, PCATCH);
2679 			if (err)
2680 				goto out;
2681 		}
2682 		err = fuse_write_directbackend(vp, uio, cred, fufh,
2683 			filesize, ioflag, pages);
2684 	} else {
2685 		SDT_PROBE2(fusefs, , vnops, trace, 1,
2686 			"buffered write of vnode");
2687 		if (!fsess_opt_writeback(vnode_mount(vp)))
2688 			ioflag |= IO_SYNC;
2689 		err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag, pid);
2690 	}
2691 	fuse_internal_clear_suid_on_write(vp, cred, uio->uio_td);
2692 
2693 out:
2694 	if (closefufh)
2695 		fuse_filehandle_close(vp, fufh, curthread, cred);
2696 
2697 	return (err);
2698 }
2699 
2700 static daddr_t
2701 fuse_gbp_getblkno(struct vnode *vp, vm_ooffset_t off)
2702 {
2703 	const int biosize = fuse_iosize(vp);
2704 
2705 	return (off / biosize);
2706 }
2707 
2708 static int
2709 fuse_gbp_getblksz(struct vnode *vp, daddr_t lbn, long *blksz)
2710 {
2711 	off_t filesize;
2712 	int err;
2713 	const int biosize = fuse_iosize(vp);
2714 
2715 	err = fuse_vnode_size(vp, &filesize, NULL, NULL);
2716 	if (err) {
2717 		/* This will turn into a SIGBUS */
2718 		return (EIO);
2719 	} else if ((off_t)lbn * biosize >= filesize) {
2720 		*blksz = 0;
2721 	} else if ((off_t)(lbn + 1) * biosize > filesize) {
2722 		*blksz = filesize - (off_t)lbn *biosize;
2723 	} else {
2724 		*blksz = biosize;
2725 	}
2726 	return (0);
2727 }
2728 
2729 /*
2730     struct vnop_getpages_args {
2731 	struct vnode *a_vp;
2732 	vm_page_t *a_m;
2733 	int a_count;
2734 	int a_reqpage;
2735     };
2736 */
2737 static int
2738 fuse_vnop_getpages(struct vop_getpages_args *ap)
2739 {
2740 	struct vnode *vp = ap->a_vp;
2741 
2742 	if (!fsess_opt_mmap(vnode_mount(vp))) {
2743 		SDT_PROBE2(fusefs, , vnops, trace, 1,
2744 			"called on non-cacheable vnode??\n");
2745 		return (VM_PAGER_ERROR);
2746 	}
2747 
2748 	return (vfs_bio_getpages(vp, ap->a_m, ap->a_count, ap->a_rbehind,
2749 	    ap->a_rahead, fuse_gbp_getblkno, fuse_gbp_getblksz));
2750 }
2751 
2752 static const char extattr_namespace_separator = '.';
2753 
2754 /*
2755     struct vop_getextattr_args {
2756 	struct vop_generic_args a_gen;
2757 	struct vnode *a_vp;
2758 	int a_attrnamespace;
2759 	const char *a_name;
2760 	struct uio *a_uio;
2761 	size_t *a_size;
2762 	struct ucred *a_cred;
2763 	struct thread *a_td;
2764     };
2765 */
2766 static int
2767 fuse_vnop_getextattr(struct vop_getextattr_args *ap)
2768 {
2769 	struct vnode *vp = ap->a_vp;
2770 	struct uio *uio = ap->a_uio;
2771 	struct fuse_dispatcher fdi;
2772 	struct fuse_getxattr_in *get_xattr_in;
2773 	struct fuse_getxattr_out *get_xattr_out;
2774 	struct mount *mp = vnode_mount(vp);
2775 	struct thread *td = ap->a_td;
2776 	struct ucred *cred = ap->a_cred;
2777 	char *prefix;
2778 	char *attr_str;
2779 	size_t len;
2780 	int err;
2781 
2782 	if (fuse_isdeadfs(vp))
2783 		return (EXTERROR(ENXIO, "This FUSE session is about "
2784 		    "to be closed"));
2785 
2786 	if (fsess_not_impl(mp, FUSE_GETXATTR))
2787 		return (EXTERROR(EOPNOTSUPP, "This server does not implement "
2788 		    "extended attributes"));
2789 
2790 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
2791 	if (err)
2792 		return err;
2793 
2794 	/* Default to looking for user attributes. */
2795 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2796 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2797 	else
2798 		prefix = EXTATTR_NAMESPACE_USER_STRING;
2799 
2800 	len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2801 	    strlen(ap->a_name) + 1;
2802 
2803 	fdisp_init(&fdi, len + sizeof(*get_xattr_in));
2804 	fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
2805 
2806 	get_xattr_in = fdi.indata;
2807 	/*
2808 	 * Check to see whether we're querying the available size or
2809 	 * issuing the actual request.  If we pass in 0, we get back struct
2810 	 * fuse_getxattr_out.  If we pass in a non-zero size, we get back
2811 	 * that much data, without the struct fuse_getxattr_out header.
2812 	 */
2813 	if (uio == NULL)
2814 		get_xattr_in->size = 0;
2815 	else
2816 		get_xattr_in->size = uio->uio_resid;
2817 
2818 	attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
2819 	snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2820 	    ap->a_name);
2821 
2822 	err = fdisp_wait_answ(&fdi);
2823 	if (err != 0) {
2824 		if (err == ENOSYS) {
2825 			fsess_set_notimpl(mp, FUSE_GETXATTR);
2826 			err = (EXTERROR(EOPNOTSUPP, "This server does not "
2827 			    "implement extended attributes"));
2828 		}
2829 		goto out;
2830 	}
2831 
2832 	get_xattr_out = fdi.answ;
2833 
2834 	if (ap->a_size != NULL)
2835 		*ap->a_size = get_xattr_out->size;
2836 
2837 	if (uio != NULL)
2838 		err = uiomove(fdi.answ, fdi.iosize, uio);
2839 
2840 out:
2841 	fdisp_destroy(&fdi);
2842 	return (err);
2843 }
2844 
2845 /*
2846     struct vop_setextattr_args {
2847 	struct vop_generic_args a_gen;
2848 	struct vnode *a_vp;
2849 	int a_attrnamespace;
2850 	const char *a_name;
2851 	struct uio *a_uio;
2852 	struct ucred *a_cred;
2853 	struct thread *a_td;
2854     };
2855 */
2856 static int
2857 fuse_vnop_setextattr(struct vop_setextattr_args *ap)
2858 {
2859 	struct vnode *vp = ap->a_vp;
2860 	struct uio *uio = ap->a_uio;
2861 	struct fuse_dispatcher fdi;
2862 	struct fuse_setxattr_in *set_xattr_in;
2863 	struct mount *mp = vnode_mount(vp);
2864 	struct thread *td = ap->a_td;
2865 	struct ucred *cred = ap->a_cred;
2866 	size_t struct_size = FUSE_COMPAT_SETXATTR_IN_SIZE;
2867 	char *prefix;
2868 	size_t len;
2869 	char *attr_str;
2870 	int err;
2871 
2872 	if (fuse_isdeadfs(vp))
2873 		return (EXTERROR(ENXIO, "This FUSE session is about "
2874 		    "to be closed"));
2875 
2876 	if (fsess_not_impl(mp, FUSE_SETXATTR))
2877 		return (EXTERROR(EOPNOTSUPP, "This server does not implement "
2878 		    "setting extended attributes"));
2879 
2880 	if (vfs_isrdonly(mp))
2881 		return EROFS;
2882 
2883 	/* Deleting xattrs must use VOP_DELETEEXTATTR instead */
2884 	if (ap->a_uio == NULL) {
2885 		/*
2886 		 * If we got here as fallback from VOP_DELETEEXTATTR, then
2887 		 * return EOPNOTSUPP.
2888 		 */
2889 		if (fsess_not_impl(mp, FUSE_REMOVEXATTR))
2890 			return (EXTERROR(EOPNOTSUPP, "This server does not "
2891 			    "implement removing extended attributes"));
2892 		else
2893 			return (EXTERROR(EINVAL, "DELETEEXTATTR should be used "
2894 			    "to remove extattrs"));
2895 	}
2896 
2897 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
2898 		VWRITE);
2899 	if (err)
2900 		return err;
2901 
2902 	/* Default to looking for user attributes. */
2903 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2904 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2905 	else
2906 		prefix = EXTATTR_NAMESPACE_USER_STRING;
2907 
2908 	len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2909 	    strlen(ap->a_name) + 1;
2910 
2911 	/* older FUSE servers  use a smaller fuse_setxattr_in struct*/
2912 	if (fuse_get_mpdata(mp)->dataflags & FSESS_SETXATTR_EXT)
2913 		struct_size = sizeof(*set_xattr_in);
2914 
2915 	fdisp_init(&fdi, len + struct_size + uio->uio_resid);
2916 	fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
2917 
2918 	set_xattr_in = fdi.indata;
2919 	set_xattr_in->size = uio->uio_resid;
2920 
2921 	if (fuse_get_mpdata(mp)->dataflags & FSESS_SETXATTR_EXT) {
2922 		set_xattr_in->setxattr_flags = 0;
2923 		set_xattr_in->padding = 0;
2924 	}
2925 
2926 	attr_str = (char *)fdi.indata + struct_size;
2927 	snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2928 	    ap->a_name);
2929 
2930 	err = uiomove((char *)fdi.indata + struct_size + len,
2931 	    uio->uio_resid, uio);
2932 	if (err != 0) {
2933 		goto out;
2934 	}
2935 
2936 	err = fdisp_wait_answ(&fdi);
2937 
2938 	if (err == ENOSYS) {
2939 		fsess_set_notimpl(mp, FUSE_SETXATTR);
2940 		err = EXTERROR(EOPNOTSUPP, "This server does not implement "
2941 		    "setting extended attributes");
2942 	}
2943 	if (err == ERESTART) {
2944 		/* Can't restart after calling uiomove */
2945 		err = EINTR;
2946 	}
2947 
2948 out:
2949 	fdisp_destroy(&fdi);
2950 	return (err);
2951 }
2952 
2953 /*
2954  * The Linux / FUSE extended attribute list is simply a collection of
2955  * NUL-terminated strings.  The FreeBSD extended attribute list is a single
2956  * byte length followed by a non-NUL terminated string.  So, this allows
2957  * conversion of the Linux / FUSE format to the FreeBSD format in place.
2958  * Linux attribute names are reported with the namespace as a prefix (e.g.
2959  * "user.attribute_name"), but in FreeBSD they are reported without the
2960  * namespace prefix (e.g. "attribute_name").  So, we're going from:
2961  *
2962  * user.attr_name1\0user.attr_name2\0
2963  *
2964  * to:
2965  *
2966  * <num>attr_name1<num>attr_name2
2967  *
2968  * Where "<num>" is a single byte number of characters in the attribute name.
2969  *
2970  * Args:
2971  * prefix - exattr namespace prefix string
2972  * list, list_len - input list with namespace prefixes
2973  * bsd_list, bsd_list_len - output list compatible with bsd vfs
2974  */
2975 static int
2976 fuse_xattrlist_convert(struct fuse_data *data, char *prefix, const char *list,
2977     int list_len, char *bsd_list, int *bsd_list_len)
2978 {
2979 	int len, pos, dist_to_next, prefix_len;
2980 
2981 	pos = 0;
2982 	*bsd_list_len = 0;
2983 	prefix_len = strlen(prefix);
2984 
2985 	while (pos < list_len && list[pos] != '\0') {
2986 		dist_to_next = strnlen(&list[pos], list_len - pos - 1) + 1;
2987 		if (list[pos + dist_to_next - 1] != '\0') {
2988 			fuse_warn(data, FSESS_WARN_LSEXTATTR_NUL,
2989 				"The FUSE server returned a non nul-terminated "
2990 				"LISTXATTR response.");
2991 			return (EXTERROR(EIO,
2992 				"The FUSE server returned a malformed list"));
2993 		}
2994 		if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
2995 		    list[pos + prefix_len] == extattr_namespace_separator) {
2996 			len = dist_to_next -
2997 			    (prefix_len + sizeof(extattr_namespace_separator)) - 1;
2998 			if (len >= EXTATTR_MAXNAMELEN)
2999 				return (ENAMETOOLONG);
3000 
3001 			bsd_list[*bsd_list_len] = len;
3002 			memcpy(&bsd_list[*bsd_list_len + 1],
3003 			    &list[pos + prefix_len +
3004 			    sizeof(extattr_namespace_separator)], len);
3005 
3006 			*bsd_list_len += len + 1;
3007 		}
3008 
3009 		pos += dist_to_next;
3010 	}
3011 
3012 	return (0);
3013 }
3014 
3015 /*
3016  * List extended attributes
3017  *
3018  * The FUSE_LISTXATTR operation is based on Linux's listxattr(2) syscall, which
3019  * has a number of differences compared to its FreeBSD equivalent,
3020  * extattr_list_file:
3021  *
3022  * - FUSE_LISTXATTR returns all extended attributes across all namespaces,
3023  *   whereas listxattr(2) only returns attributes for a single namespace
3024  * - FUSE_LISTXATTR prepends each attribute name with "namespace."
3025  * - If the provided buffer is not large enough to hold the result,
3026  *   FUSE_LISTXATTR should return ERANGE, whereas listxattr is expected to
3027  *   return as many results as will fit.
3028  */
3029 /*
3030     struct vop_listextattr_args {
3031 	struct vop_generic_args a_gen;
3032 	struct vnode *a_vp;
3033 	int a_attrnamespace;
3034 	struct uio *a_uio;
3035 	size_t *a_size;
3036 	struct ucred *a_cred;
3037 	struct thread *a_td;
3038     };
3039 */
3040 static int
3041 fuse_vnop_listextattr(struct vop_listextattr_args *ap)
3042 {
3043 	struct vnode *vp = ap->a_vp;
3044 	struct uio *uio = ap->a_uio;
3045 	struct fuse_dispatcher fdi;
3046 	struct fuse_listxattr_in *list_xattr_in;
3047 	struct fuse_listxattr_out *list_xattr_out;
3048 	struct mount *mp = vnode_mount(vp);
3049 	struct fuse_data *data = fuse_get_mpdata(mp);
3050 	struct thread *td = ap->a_td;
3051 	struct ucred *cred = ap->a_cred;
3052 	char *prefix;
3053 	char *bsd_list = NULL;
3054 	char *linux_list;
3055 	int bsd_list_len;
3056 	int linux_list_len;
3057 	int err;
3058 
3059 	if (fuse_isdeadfs(vp))
3060 		return (EXTERROR(ENXIO, "This FUSE session is about "
3061 		    "to be closed"));
3062 
3063 	if (fsess_not_impl(mp, FUSE_LISTXATTR))
3064 		return (EXTERROR(EOPNOTSUPP, "This server does not implement "
3065 		    "extended attributes"));
3066 
3067 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
3068 	if (err)
3069 		return err;
3070 
3071 	/*
3072 	 * Add space for a NUL and the period separator if enabled.
3073 	 * Default to looking for user attributes.
3074 	 */
3075 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
3076 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
3077 	else
3078 		prefix = EXTATTR_NAMESPACE_USER_STRING;
3079 
3080 	fdisp_init(&fdi, sizeof(*list_xattr_in));
3081 	fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
3082 
3083 	/*
3084 	 * Retrieve Linux / FUSE compatible list size.
3085 	 */
3086 	list_xattr_in = fdi.indata;
3087 	list_xattr_in->size = 0;
3088 
3089 	err = fdisp_wait_answ(&fdi);
3090 	if (err != 0) {
3091 		if (err == ENOSYS) {
3092 			fsess_set_notimpl(mp, FUSE_LISTXATTR);
3093 			err = EXTERROR(EOPNOTSUPP, "This server does not "
3094 			    "implement extended attributes");
3095 		}
3096 		goto out;
3097 	}
3098 
3099 	list_xattr_out = fdi.answ;
3100 	linux_list_len = list_xattr_out->size;
3101 	if (linux_list_len == 0) {
3102 		if (ap->a_size != NULL)
3103 			*ap->a_size = linux_list_len;
3104 		goto out;
3105 	}
3106 
3107 	/*
3108 	 * Retrieve Linux / FUSE compatible list values.
3109 	 */
3110 	fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
3111 	list_xattr_in = fdi.indata;
3112 	list_xattr_in->size = linux_list_len;
3113 
3114 	err = fdisp_wait_answ(&fdi);
3115 	if (err == ERANGE) {
3116 		/*
3117 		 * Race detected.  The attribute list must've grown since the
3118 		 * first FUSE_LISTXATTR call.  Start over.  Go all the way back
3119 		 * to userland so we can process signals, if necessary, before
3120 		 * restarting.
3121 		 */
3122 		err = ERESTART;
3123 		goto out;
3124 	} else if (err != 0)
3125 		goto out;
3126 
3127 	linux_list = fdi.answ;
3128 	/* FUSE doesn't allow the server to return more data than requested */
3129 	if (fdi.iosize > linux_list_len) {
3130 		fuse_warn(data, FSESS_WARN_LSEXTATTR_LONG,
3131 			"server returned "
3132 			"more extended attribute data than requested; "
3133 			"should've returned ERANGE instead.");
3134 	} else {
3135 		/* But returning less data is fine */
3136 		linux_list_len = fdi.iosize;
3137 	}
3138 
3139 	/*
3140 	 * Retrieve the BSD compatible list values.
3141 	 * The Linux / FUSE attribute list format isn't the same
3142 	 * as FreeBSD's format. So we need to transform it into
3143 	 * FreeBSD's format before giving it to the user.
3144 	 */
3145 	bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
3146 	err = fuse_xattrlist_convert(data, prefix, linux_list, linux_list_len,
3147 	    bsd_list, &bsd_list_len);
3148 	if (err != 0)
3149 		goto out;
3150 
3151 	if (ap->a_size != NULL)
3152 		*ap->a_size = bsd_list_len;
3153 
3154 	if (uio != NULL)
3155 		err = uiomove(bsd_list, bsd_list_len, uio);
3156 
3157 out:
3158 	free(bsd_list, M_TEMP);
3159 	fdisp_destroy(&fdi);
3160 	return (err);
3161 }
3162 
3163 /*
3164     struct vop_deallocate_args {
3165 	struct vop_generic_args a_gen;
3166 	struct vnode *a_vp;
3167 	off_t *a_offset;
3168 	off_t *a_len;
3169 	int a_flags;
3170 	int a_ioflag;
3171         struct ucred *a_cred;
3172     };
3173 */
3174 static int
3175 fuse_vnop_deallocate(struct vop_deallocate_args *ap)
3176 {
3177 	struct vnode *vp = ap->a_vp;
3178 	struct mount *mp = vnode_mount(vp);
3179 	struct fuse_filehandle *fufh;
3180 	struct fuse_dispatcher fdi;
3181 	struct fuse_fallocate_in *ffi;
3182 	struct ucred *cred = ap->a_cred;
3183 	pid_t pid = curthread->td_proc->p_pid;
3184 	off_t *len = ap->a_len;
3185 	off_t *offset = ap->a_offset;
3186 	int ioflag = ap->a_ioflag;
3187 	off_t filesize;
3188 	int err;
3189 	bool closefufh = false;
3190 
3191 	if (fuse_isdeadfs(vp))
3192 		return (EXTERROR(ENXIO, "This FUSE session is about "
3193 		    "to be closed"));
3194 
3195 	if (vfs_isrdonly(mp))
3196 		return (EROFS);
3197 
3198 	if (fsess_not_impl(mp, FUSE_FALLOCATE))
3199 		goto fallback;
3200 
3201 	err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
3202 	if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
3203 		/*
3204 		 * nfsd will do I/O without first doing VOP_OPEN.  We
3205 		 * must implicitly open the file here
3206 		 */
3207 		err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred);
3208 		closefufh = true;
3209 	}
3210 	if (err)
3211 		return (err);
3212 
3213 	fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
3214 
3215 	err = fuse_vnode_size(vp, &filesize, cred, curthread);
3216 	if (err)
3217 		goto out;
3218 	err = fuse_inval_buf_range(vp, filesize, *offset, *offset + *len, 0);
3219 	if (err)
3220 		goto out;
3221 
3222 	fdisp_init(&fdi, sizeof(*ffi));
3223 	fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred);
3224 	ffi = fdi.indata;
3225 	ffi->fh = fufh->fh_id;
3226 	ffi->offset = *offset;
3227 	ffi->length = *len;
3228 	/*
3229 	 * FreeBSD's fspacectl is equivalent to Linux's fallocate with
3230 	 * mode == FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE
3231 	 */
3232 	ffi->mode = FUSE_FALLOC_FL_PUNCH_HOLE | FUSE_FALLOC_FL_KEEP_SIZE;
3233 	err = fdisp_wait_answ(&fdi);
3234 
3235 	if (err == ENOSYS) {
3236 		fdisp_destroy(&fdi);
3237 		fsess_set_notimpl(mp, FUSE_FALLOCATE);
3238 		goto fallback;
3239 	} else if (err == EOPNOTSUPP) {
3240 		/*
3241 		 * The file system server does not support FUSE_FALLOCATE with
3242 		 * the supplied mode for this particular file.
3243 		 */
3244 		fdisp_destroy(&fdi);
3245 		goto fallback;
3246 	} else if (!err) {
3247 		/*
3248 		 * Clip the returned offset to EoF.  Do it here rather than
3249 		 * before FUSE_FALLOCATE just in case the kernel's cached file
3250 		 * size is out of date.  Unfortunately, FUSE does not return
3251 		 * any information about filesize from that operation.
3252 		 */
3253 		*offset = MIN(*offset + *len, filesize);
3254 		*len = 0;
3255 		fuse_vnode_undirty_cached_timestamps(vp, false);
3256 		fuse_internal_clear_suid_on_write(vp, cred, curthread);
3257 
3258 		if (ioflag & IO_SYNC)
3259 			err = fuse_internal_fsync(vp, curthread, MNT_WAIT,
3260 			    false);
3261 	}
3262 
3263 	fdisp_destroy(&fdi);
3264 out:
3265 	if (closefufh)
3266 		fuse_filehandle_close(vp, fufh, curthread, cred);
3267 
3268 	return (err);
3269 
3270 fallback:
3271 	if (closefufh)
3272 		fuse_filehandle_close(vp, fufh, curthread, cred);
3273 
3274 	return (vop_stddeallocate(ap));
3275 }
3276 
3277 /*
3278    struct vop_delayed_setsize_args {
3279 	struct vop_generic_args a_gen;
3280 	struct vnode *a_vp;
3281   };
3282  */
3283 static int
3284 fuse_vnop_delayed_setsize(struct vop_delayed_setsize_args *ap)
3285 {
3286 	struct vnode *vp = ap->a_vp;
3287 	struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
3288 	bool shrink = (fvdat->flag & FN_DELAYED_TRUNCATE) != 0;
3289 	int err;
3290 
3291 	if (!fvdat)
3292 		return (0);
3293 
3294 	err = fuse_vnode_setsize_immediate(vp, shrink);
3295 	fvdat->flag &= ~FN_DELAYED_TRUNCATE;
3296 
3297 	return (err);
3298 }
3299 
3300 /*
3301     struct vop_deleteextattr_args {
3302 	struct vop_generic_args a_gen;
3303 	struct vnode *a_vp;
3304 	int a_attrnamespace;
3305 	const char *a_name;
3306 	struct ucred *a_cred;
3307 	struct thread *a_td;
3308     };
3309 */
3310 static int
3311 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
3312 {
3313 	struct vnode *vp = ap->a_vp;
3314 	struct fuse_dispatcher fdi;
3315 	struct mount *mp = vnode_mount(vp);
3316 	struct thread *td = ap->a_td;
3317 	struct ucred *cred = ap->a_cred;
3318 	char *prefix;
3319 	size_t len;
3320 	char *attr_str;
3321 	int err;
3322 
3323 	if (fuse_isdeadfs(vp))
3324 		return (EXTERROR(ENXIO, "This FUSE session is about "
3325 		    "to be closed"));
3326 
3327 	if (fsess_not_impl(mp, FUSE_REMOVEXATTR))
3328 		return (EXTERROR(EOPNOTSUPP, "This server does not implement "
3329 		    "removing extended attributes"));
3330 
3331 	if (vfs_isrdonly(mp))
3332 		return EROFS;
3333 
3334 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
3335 		VWRITE);
3336 	if (err)
3337 		return err;
3338 
3339 	/* Default to looking for user attributes. */
3340 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
3341 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
3342 	else
3343 		prefix = EXTATTR_NAMESPACE_USER_STRING;
3344 
3345 	len = strlen(prefix) + sizeof(extattr_namespace_separator) +
3346 	    strlen(ap->a_name) + 1;
3347 
3348 	fdisp_init(&fdi, len);
3349 	fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
3350 
3351 	attr_str = fdi.indata;
3352 	snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
3353 	    ap->a_name);
3354 
3355 	err = fdisp_wait_answ(&fdi);
3356 	if (err == ENOSYS) {
3357 		fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
3358 		err = EXTERROR(EOPNOTSUPP, "This server does not implement "
3359 		    "removing extended attributes");
3360 	}
3361 
3362 	fdisp_destroy(&fdi);
3363 	return (err);
3364 }
3365 
3366 /*
3367     struct vnop_print_args {
3368 	struct vnode *a_vp;
3369     };
3370 */
3371 static int
3372 fuse_vnop_print(struct vop_print_args *ap)
3373 {
3374 	struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
3375 
3376 	printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
3377 	    (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
3378 	    (uintmax_t)fvdat->nlookup,
3379 	    fvdat->flag);
3380 
3381 	return 0;
3382 }
3383 
3384 /*
3385  * Get an NFS filehandle for a FUSE file.
3386  *
3387  * This will only work for FUSE file systems that guarantee the uniqueness of
3388  * nodeid:generation, which most don't.
3389  */
3390 /*
3391 vop_vptofh {
3392 	IN struct vnode *a_vp;
3393 	IN struct fid *a_fhp;
3394 };
3395 */
3396 static int
3397 fuse_vnop_vptofh(struct vop_vptofh_args *ap)
3398 {
3399 	struct vnode *vp = ap->a_vp;
3400 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
3401 	struct fuse_fid *fhp = (struct fuse_fid *)(ap->a_fhp);
3402 	_Static_assert(sizeof(struct fuse_fid) <= sizeof(struct fid),
3403 		"FUSE fid type is too big");
3404 	struct mount *mp = vnode_mount(vp);
3405 	struct fuse_data *data = fuse_get_mpdata(mp);
3406 	struct vattr va;
3407 	int err;
3408 
3409 	if (!(data->dataflags & FSESS_EXPORT_SUPPORT)) {
3410 		/* NFS requires lookups for "." and ".." */
3411 		SDT_PROBE2(fusefs, , vnops, trace, 1,
3412 			"VOP_VPTOFH without FUSE_EXPORT_SUPPORT");
3413 		return (EXTERROR(EOPNOTSUPP, "This server is "
3414 		    "missing FUSE_EXPORT_SUPPORT"));
3415 	}
3416 	if ((mp->mnt_flag & MNT_EXPORTED) &&
3417 		fsess_is_impl(mp, FUSE_OPENDIR))
3418 	{
3419 		/*
3420 		 * NFS is stateless, so nfsd must reopen a directory on every
3421 		 * call to VOP_READDIR, passing in the d_off field from the
3422 		 * final dirent of the previous invocation.  But if the server
3423 		 * implements FUSE_OPENDIR, the FUSE protocol does not
3424 		 * guarantee that d_off will be valid after a directory is
3425 		 * closed and reopened.  So prohibit exporting FUSE file
3426 		 * systems that implement FUSE_OPENDIR.
3427 		 *
3428 		 * But userspace NFS servers don't have this problem.
3429                  */
3430 		SDT_PROBE2(fusefs, , vnops, trace, 1,
3431 			"VOP_VPTOFH with FUSE_OPENDIR");
3432 		return (EXTERROR(EOPNOTSUPP, "This server implements "
3433 		    "FUSE_OPENDIR so is not compatible with getfh"));
3434 	}
3435 
3436 	err = fuse_internal_getattr(vp, &va, curthread->td_ucred, curthread);
3437 	if (err)
3438 		return err;
3439 
3440 	/*ip = VTOI(ap->a_vp);*/
3441 	/*ufhp = (struct ufid *)ap->a_fhp;*/
3442 	fhp->len = sizeof(struct fuse_fid);
3443 	fhp->nid = fvdat->nid;
3444 	if (fvdat->generation <= UINT32_MAX)
3445 		fhp->gen = fvdat->generation;
3446 	else
3447 		return (EXTERROR(EOVERFLOW, "inode generation "
3448 		    "number overflow"));
3449 	return (0);
3450 }
3451