xref: /freebsd-12.1/sys/fs/fuse/fuse_vnops.c (revision 08409450)
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/cdefs.h>
64 __FBSDID("$FreeBSD$");
65 
66 #include <sys/param.h>
67 #include <sys/module.h>
68 #include <sys/systm.h>
69 #include <sys/errno.h>
70 #include <sys/kernel.h>
71 #include <sys/conf.h>
72 #include <sys/uio.h>
73 #include <sys/malloc.h>
74 #include <sys/queue.h>
75 #include <sys/limits.h>
76 #include <sys/lock.h>
77 #include <sys/rwlock.h>
78 #include <sys/sx.h>
79 #include <sys/proc.h>
80 #include <sys/mount.h>
81 #include <sys/vnode.h>
82 #include <sys/namei.h>
83 #include <sys/extattr.h>
84 #include <sys/stat.h>
85 #include <sys/unistd.h>
86 #include <sys/filedesc.h>
87 #include <sys/file.h>
88 #include <sys/fcntl.h>
89 #include <sys/dirent.h>
90 #include <sys/bio.h>
91 #include <sys/buf.h>
92 #include <sys/sysctl.h>
93 #include <sys/vmmeter.h>
94 
95 #include <vm/vm.h>
96 #include <vm/vm_extern.h>
97 #include <vm/pmap.h>
98 #include <vm/vm_map.h>
99 #include <vm/vm_page.h>
100 #include <vm/vm_param.h>
101 #include <vm/vm_object.h>
102 #include <vm/vm_pager.h>
103 #include <vm/vnode_pager.h>
104 #include <vm/vm_object.h>
105 
106 #include "fuse.h"
107 #include "fuse_file.h"
108 #include "fuse_internal.h"
109 #include "fuse_ipc.h"
110 #include "fuse_node.h"
111 #include "fuse_io.h"
112 
113 #include <sys/priv.h>
114 
115 /* Maximum number of hardlinks to a single FUSE file */
116 #define FUSE_LINK_MAX                      UINT32_MAX
117 
118 SDT_PROVIDER_DECLARE(fusefs);
119 /*
120  * Fuse trace probe:
121  * arg0: verbosity.  Higher numbers give more verbose messages
122  * arg1: Textual message
123  */
124 SDT_PROBE_DEFINE2(fusefs, , vnops, trace, "int", "char*");
125 
126 /* vnode ops */
127 static vop_access_t fuse_vnop_access;
128 static vop_advlock_t fuse_vnop_advlock;
129 static vop_bmap_t fuse_vnop_bmap;
130 static vop_close_t fuse_fifo_close;
131 static vop_close_t fuse_vnop_close;
132 static vop_create_t fuse_vnop_create;
133 static vop_deleteextattr_t fuse_vnop_deleteextattr;
134 static vop_fdatasync_t fuse_vnop_fdatasync;
135 static vop_fsync_t fuse_vnop_fsync;
136 static vop_getattr_t fuse_vnop_getattr;
137 static vop_getextattr_t fuse_vnop_getextattr;
138 static vop_inactive_t fuse_vnop_inactive;
139 static vop_link_t fuse_vnop_link;
140 static vop_listextattr_t fuse_vnop_listextattr;
141 static vop_lookup_t fuse_vnop_lookup;
142 static vop_mkdir_t fuse_vnop_mkdir;
143 static vop_mknod_t fuse_vnop_mknod;
144 static vop_open_t fuse_vnop_open;
145 static vop_pathconf_t fuse_vnop_pathconf;
146 static vop_read_t fuse_vnop_read;
147 static vop_readdir_t fuse_vnop_readdir;
148 static vop_readlink_t fuse_vnop_readlink;
149 static vop_reclaim_t fuse_vnop_reclaim;
150 static vop_remove_t fuse_vnop_remove;
151 static vop_rename_t fuse_vnop_rename;
152 static vop_rmdir_t fuse_vnop_rmdir;
153 static vop_setattr_t fuse_vnop_setattr;
154 static vop_setextattr_t fuse_vnop_setextattr;
155 static vop_strategy_t fuse_vnop_strategy;
156 static vop_symlink_t fuse_vnop_symlink;
157 static vop_write_t fuse_vnop_write;
158 static vop_getpages_t fuse_vnop_getpages;
159 static vop_print_t fuse_vnop_print;
160 static vop_vptofh_t fuse_vnop_vptofh;
161 
162 struct vop_vector fuse_fifoops = {
163 	.vop_default =		&fifo_specops,
164 	.vop_access =		fuse_vnop_access,
165 	.vop_close =		fuse_fifo_close,
166 	.vop_fsync =		fuse_vnop_fsync,
167 	.vop_getattr =		fuse_vnop_getattr,
168 	.vop_inactive =		fuse_vnop_inactive,
169 	.vop_pathconf =		fuse_vnop_pathconf,
170 	.vop_print =		fuse_vnop_print,
171 	.vop_read =		VOP_PANIC,
172 	.vop_reclaim =		fuse_vnop_reclaim,
173 	.vop_setattr =		fuse_vnop_setattr,
174 	.vop_write =		VOP_PANIC,
175 	.vop_vptofh =		fuse_vnop_vptofh,
176 };
177 
178 struct vop_vector fuse_vnops = {
179 	.vop_allocate =	VOP_EINVAL,
180 	.vop_default = &default_vnodeops,
181 	.vop_access = fuse_vnop_access,
182 	.vop_advlock = fuse_vnop_advlock,
183 	.vop_bmap = fuse_vnop_bmap,
184 	.vop_close = fuse_vnop_close,
185 	.vop_create = fuse_vnop_create,
186 	.vop_deleteextattr = fuse_vnop_deleteextattr,
187 	.vop_fsync = fuse_vnop_fsync,
188 	.vop_fdatasync = fuse_vnop_fdatasync,
189 	.vop_getattr = fuse_vnop_getattr,
190 	.vop_getextattr = fuse_vnop_getextattr,
191 	.vop_inactive = fuse_vnop_inactive,
192 	/*
193 	 * TODO: implement vop_ioctl after upgrading to protocol 7.16.
194 	 * FUSE_IOCTL was added in 7.11, but 32-bit compat is broken until
195 	 * 7.16.
196 	 */
197 	.vop_link = fuse_vnop_link,
198 	.vop_listextattr = fuse_vnop_listextattr,
199 	.vop_lookup = fuse_vnop_lookup,
200 	.vop_mkdir = fuse_vnop_mkdir,
201 	.vop_mknod = fuse_vnop_mknod,
202 	.vop_open = fuse_vnop_open,
203 	.vop_pathconf = fuse_vnop_pathconf,
204 	/*
205 	 * TODO: implement vop_poll after upgrading to protocol 7.21.
206 	 * FUSE_POLL was added in protocol 7.11, but it's kind of broken until
207 	 * 7.21, which adds the ability for the client to choose which poll
208 	 * events it wants, and for a client to deregister a file handle
209 	 */
210 	.vop_read = fuse_vnop_read,
211 	.vop_readdir = fuse_vnop_readdir,
212 	.vop_readlink = fuse_vnop_readlink,
213 	.vop_reclaim = fuse_vnop_reclaim,
214 	.vop_remove = fuse_vnop_remove,
215 	.vop_rename = fuse_vnop_rename,
216 	.vop_rmdir = fuse_vnop_rmdir,
217 	.vop_setattr = fuse_vnop_setattr,
218 	.vop_setextattr = fuse_vnop_setextattr,
219 	.vop_strategy = fuse_vnop_strategy,
220 	.vop_symlink = fuse_vnop_symlink,
221 	.vop_write = fuse_vnop_write,
222 	.vop_getpages = fuse_vnop_getpages,
223 	.vop_print = fuse_vnop_print,
224 	.vop_vptofh = fuse_vnop_vptofh,
225 };
226 
227 int	fuse_pbuf_freecnt = -1;
228 
229 /* Check permission for extattr operations, much like extattr_check_cred */
230 static int
fuse_extattr_check_cred(struct vnode * vp,int ns,struct ucred * cred,struct thread * td,accmode_t accmode)231 fuse_extattr_check_cred(struct vnode *vp, int ns, struct ucred *cred,
232 	struct thread *td, accmode_t accmode)
233 {
234 	struct mount *mp = vnode_mount(vp);
235 	struct fuse_data *data = fuse_get_mpdata(mp);
236 
237 	/*
238 	 * Kernel-invoked always succeeds.
239 	 */
240 	if (cred == NOCRED)
241 		return (0);
242 
243 	/*
244 	 * Do not allow privileged processes in jail to directly manipulate
245 	 * system attributes.
246 	 */
247 	switch (ns) {
248 	case EXTATTR_NAMESPACE_SYSTEM:
249 		if (data->dataflags & FSESS_DEFAULT_PERMISSIONS) {
250 			return (priv_check_cred(cred, PRIV_VFS_EXTATTR_SYSTEM,
251 			    0));
252 		}
253 		/* FALLTHROUGH */
254 	case EXTATTR_NAMESPACE_USER:
255 		return (fuse_internal_access(vp, accmode, td, cred));
256 	default:
257 		return (EPERM);
258 	}
259 }
260 
261 /* Get a filehandle for a directory */
262 static int
fuse_filehandle_get_dir(struct vnode * vp,struct fuse_filehandle ** fufhp,struct ucred * cred,pid_t pid)263 fuse_filehandle_get_dir(struct vnode *vp, struct fuse_filehandle **fufhp,
264 	struct ucred *cred, pid_t pid)
265 {
266 	if (fuse_filehandle_get(vp, FREAD, fufhp, cred, pid) == 0)
267 		return 0;
268 	return fuse_filehandle_get(vp, FEXEC, fufhp, cred, pid);
269 }
270 
271 /* Send FUSE_FLUSH for this vnode */
272 static int
fuse_flush(struct vnode * vp,struct ucred * cred,pid_t pid,int fflag)273 fuse_flush(struct vnode *vp, struct ucred *cred, pid_t pid, int fflag)
274 {
275 	struct fuse_flush_in *ffi;
276 	struct fuse_filehandle *fufh;
277 	struct fuse_dispatcher fdi;
278 	struct thread *td = curthread;
279 	struct mount *mp = vnode_mount(vp);
280 	int err;
281 
282 	if (!fsess_isimpl(vnode_mount(vp), FUSE_FLUSH))
283 		return 0;
284 
285 	err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
286 	if (err)
287 		return err;
288 
289 	fdisp_init(&fdi, sizeof(*ffi));
290 	fdisp_make_vp(&fdi, FUSE_FLUSH, vp, td, cred);
291 	ffi = fdi.indata;
292 	ffi->fh = fufh->fh_id;
293 	/*
294 	 * If the file has a POSIX lock then we're supposed to set lock_owner.
295 	 * If not, then lock_owner is undefined.  So we may as well always set
296 	 * it.
297 	 */
298 	ffi->lock_owner = td->td_proc->p_pid;
299 
300 	err = fdisp_wait_answ(&fdi);
301 	if (err == ENOSYS) {
302 		fsess_set_notimpl(mp, FUSE_FLUSH);
303 		err = 0;
304 	}
305 	fdisp_destroy(&fdi);
306 	return err;
307 }
308 
309 /* Close wrapper for fifos.  */
310 static int
fuse_fifo_close(struct vop_close_args * ap)311 fuse_fifo_close(struct vop_close_args *ap)
312 {
313 	return (fifo_specops.vop_close(ap));
314 }
315 
316 /*
317     struct vnop_access_args {
318 	struct vnode *a_vp;
319 #if VOP_ACCESS_TAKES_ACCMODE_T
320 	accmode_t a_accmode;
321 #else
322 	int a_mode;
323 #endif
324 	struct ucred *a_cred;
325 	struct thread *a_td;
326     };
327 */
328 static int
fuse_vnop_access(struct vop_access_args * ap)329 fuse_vnop_access(struct vop_access_args *ap)
330 {
331 	struct vnode *vp = ap->a_vp;
332 	int accmode = ap->a_accmode;
333 	struct ucred *cred = ap->a_cred;
334 
335 	struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
336 
337 	int err;
338 
339 	if (fuse_isdeadfs(vp)) {
340 		if (vnode_isvroot(vp)) {
341 			return 0;
342 		}
343 		return ENXIO;
344 	}
345 	if (!(data->dataflags & FSESS_INITED)) {
346 		if (vnode_isvroot(vp)) {
347 			if (priv_check_cred(cred, PRIV_VFS_ADMIN, 0) ||
348 			    (fuse_match_cred(data->daemoncred, cred) == 0)) {
349 				return 0;
350 			}
351 		}
352 		return EBADF;
353 	}
354 	if (vnode_islnk(vp)) {
355 		return 0;
356 	}
357 
358 	err = fuse_internal_access(vp, accmode, ap->a_td, ap->a_cred);
359 	return err;
360 }
361 
362 /*
363  * struct vop_advlock_args {
364  *	struct vop_generic_args a_gen;
365  *	struct vnode *a_vp;
366  *	void *a_id;
367  *	int a_op;
368  *	struct flock *a_fl;
369  *	int a_flags;
370  * }
371  */
372 static int
fuse_vnop_advlock(struct vop_advlock_args * ap)373 fuse_vnop_advlock(struct vop_advlock_args *ap)
374 {
375 	struct vnode *vp = ap->a_vp;
376 	struct flock *fl = ap->a_fl;
377 	struct thread *td = curthread;
378 	struct ucred *cred = td->td_ucred;
379 	pid_t pid = td->td_proc->p_pid;
380 	struct fuse_filehandle *fufh;
381 	struct fuse_dispatcher fdi;
382 	struct fuse_lk_in *fli;
383 	struct fuse_lk_out *flo;
384 	enum fuse_opcode op;
385 	int dataflags, err;
386 	int flags = ap->a_flags;
387 
388 	dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
389 
390 	if (fuse_isdeadfs(vp)) {
391 		return ENXIO;
392 	}
393 
394 	if (!(dataflags & FSESS_POSIX_LOCKS))
395 		return vop_stdadvlock(ap);
396 	/* FUSE doesn't properly support flock until protocol 7.17 */
397 	if (flags & F_FLOCK)
398 		return vop_stdadvlock(ap);
399 
400 	err = fuse_filehandle_get_anyflags(vp, &fufh, cred, pid);
401 	if (err)
402 		return err;
403 
404 	fdisp_init(&fdi, sizeof(*fli));
405 
406 	switch(ap->a_op) {
407 	case F_GETLK:
408 		op = FUSE_GETLK;
409 		break;
410 	case F_SETLK:
411 		op = FUSE_SETLK;
412 		break;
413 	case F_SETLKW:
414 		op = FUSE_SETLKW;
415 		break;
416 	default:
417 		return EINVAL;
418 	}
419 
420 	fdisp_make_vp(&fdi, op, vp, td, cred);
421 	fli = fdi.indata;
422 	fli->fh = fufh->fh_id;
423 	fli->owner = fl->l_pid;
424 	fli->lk.start = fl->l_start;
425 	if (fl->l_len != 0)
426 		fli->lk.end = fl->l_start + fl->l_len - 1;
427 	else
428 		fli->lk.end = INT64_MAX;
429 	fli->lk.type = fl->l_type;
430 	fli->lk.pid = fl->l_pid;
431 
432 	err = fdisp_wait_answ(&fdi);
433 	fdisp_destroy(&fdi);
434 
435 	if (err == 0 && op == FUSE_GETLK) {
436 		flo = fdi.answ;
437 		fl->l_type = flo->lk.type;
438 		fl->l_pid = flo->lk.pid;
439 		if (flo->lk.type != F_UNLCK) {
440 			fl->l_start = flo->lk.start;
441 			if (flo->lk.end == INT64_MAX)
442 				fl->l_len = 0;
443 			else
444 				fl->l_len = flo->lk.end - flo->lk.start + 1;
445 			fl->l_start = flo->lk.start;
446 		}
447 	}
448 
449 	return err;
450 }
451 
452 /* {
453 	struct vnode *a_vp;
454 	daddr_t a_bn;
455 	struct bufobj **a_bop;
456 	daddr_t *a_bnp;
457 	int *a_runp;
458 	int *a_runb;
459 } */
460 static int
fuse_vnop_bmap(struct vop_bmap_args * ap)461 fuse_vnop_bmap(struct vop_bmap_args *ap)
462 {
463 	struct vnode *vp = ap->a_vp;
464 	struct bufobj **bo = ap->a_bop;
465 	struct thread *td = curthread;
466 	struct mount *mp;
467 	struct fuse_dispatcher fdi;
468 	struct fuse_bmap_in *fbi;
469 	struct fuse_bmap_out *fbo;
470 	struct fuse_data *data;
471 	uint64_t biosize;
472 	off_t filesize;
473 	daddr_t lbn = ap->a_bn;
474 	daddr_t *pbn = ap->a_bnp;
475 	int *runp = ap->a_runp;
476 	int *runb = ap->a_runb;
477 	int error = 0;
478 	int maxrun;
479 
480 	if (fuse_isdeadfs(vp)) {
481 		return ENXIO;
482 	}
483 
484 	mp = vnode_mount(vp);
485 	data = fuse_get_mpdata(mp);
486 	biosize = fuse_iosize(vp);
487 	maxrun = MIN(vp->v_mount->mnt_iosize_max / biosize - 1,
488 		data->max_readahead_blocks);
489 
490 	if (bo != NULL)
491 		*bo = &vp->v_bufobj;
492 
493 	/*
494 	 * The FUSE_BMAP operation does not include the runp and runb
495 	 * variables, so we must guess.  Report nonzero contiguous runs so
496 	 * cluster_read will combine adjacent reads.  It's worthwhile to reduce
497 	 * upcalls even if we don't know the true physical layout of the file.
498 	 *
499 	 * FUSE file systems may opt out of read clustering in two ways:
500 	 * * mounting with -onoclusterr
501 	 * * Setting max_readahead <= maxbcachebuf during FUSE_INIT
502 	 */
503 	if (runb != NULL)
504 		*runb = MIN(lbn, maxrun);
505 	if (runp != NULL) {
506 		error = fuse_vnode_size(vp, &filesize, td->td_ucred, td);
507 		if (error == 0)
508 			*runp = MIN(MAX(0, filesize / (off_t)biosize - lbn - 1),
509 				    maxrun);
510 		else
511 			*runp = 0;
512 	}
513 
514 	if (fsess_isimpl(mp, FUSE_BMAP)) {
515 		fdisp_init(&fdi, sizeof(*fbi));
516 		fdisp_make_vp(&fdi, FUSE_BMAP, vp, td, td->td_ucred);
517 		fbi = fdi.indata;
518 		fbi->block = lbn;
519 		fbi->blocksize = biosize;
520 		error = fdisp_wait_answ(&fdi);
521 		if (error == ENOSYS) {
522 			fdisp_destroy(&fdi);
523 			fsess_set_notimpl(mp, FUSE_BMAP);
524 			error = 0;
525 		} else {
526 			fbo = fdi.answ;
527 			if (error == 0 && pbn != NULL)
528 				*pbn = fbo->block;
529 			fdisp_destroy(&fdi);
530 			return error;
531 		}
532 	}
533 
534 	/* If the daemon doesn't support BMAP, make up a sensible default */
535 	if (pbn != NULL)
536 		*pbn = lbn * btodb(biosize);
537 	return (error);
538 }
539 
540 /*
541     struct vop_close_args {
542 	struct vnode *a_vp;
543 	int  a_fflag;
544 	struct ucred *a_cred;
545 	struct thread *a_td;
546     };
547 */
548 static int
fuse_vnop_close(struct vop_close_args * ap)549 fuse_vnop_close(struct vop_close_args *ap)
550 {
551 	struct vnode *vp = ap->a_vp;
552 	struct ucred *cred = ap->a_cred;
553 	int fflag = ap->a_fflag;
554 	struct thread *td = ap->a_td;
555 	pid_t pid = td->td_proc->p_pid;
556 	int err = 0;
557 
558 	if (fuse_isdeadfs(vp))
559 		return 0;
560 	if (vnode_isdir(vp))
561 		return 0;
562 	if (fflag & IO_NDELAY)
563 		return 0;
564 
565 	err = fuse_flush(vp, cred, pid, fflag);
566 	/* TODO: close the file handle, if we're sure it's no longer used */
567 	if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
568 		fuse_vnode_savesize(vp, cred, td->td_proc->p_pid);
569 	}
570 	return err;
571 }
572 
573 static void
fdisp_make_mknod_for_fallback(struct fuse_dispatcher * fdip,struct componentname * cnp,struct vnode * dvp,uint64_t parentnid,struct thread * td,struct ucred * cred,mode_t mode,enum fuse_opcode * op)574 fdisp_make_mknod_for_fallback(
575 	struct fuse_dispatcher *fdip,
576 	struct componentname *cnp,
577 	struct vnode *dvp,
578 	uint64_t parentnid,
579 	struct thread *td,
580 	struct ucred *cred,
581 	mode_t mode,
582 	enum fuse_opcode *op)
583 {
584 	struct fuse_mknod_in *fmni;
585 
586 	fdisp_init(fdip, sizeof(*fmni) + cnp->cn_namelen + 1);
587 	*op = FUSE_MKNOD;
588 	fdisp_make(fdip, *op, vnode_mount(dvp), parentnid, td, cred);
589 	fmni = fdip->indata;
590 	fmni->mode = mode;
591 	fmni->rdev = 0;
592 	memcpy((char *)fdip->indata + sizeof(*fmni), cnp->cn_nameptr,
593 	    cnp->cn_namelen);
594 	((char *)fdip->indata)[sizeof(*fmni) + cnp->cn_namelen] = '\0';
595 }
596 /*
597     struct vnop_create_args {
598 	struct vnode *a_dvp;
599 	struct vnode **a_vpp;
600 	struct componentname *a_cnp;
601 	struct vattr *a_vap;
602     };
603 */
604 static int
fuse_vnop_create(struct vop_create_args * ap)605 fuse_vnop_create(struct vop_create_args *ap)
606 {
607 	struct vnode *dvp = ap->a_dvp;
608 	struct vnode **vpp = ap->a_vpp;
609 	struct componentname *cnp = ap->a_cnp;
610 	struct vattr *vap = ap->a_vap;
611 	struct thread *td = cnp->cn_thread;
612 	struct ucred *cred = cnp->cn_cred;
613 
614 	struct fuse_data *data;
615 	struct fuse_create_in *fci;
616 	struct fuse_entry_out *feo;
617 	struct fuse_open_out *foo;
618 	struct fuse_dispatcher fdi, fdi2;
619 	struct fuse_dispatcher *fdip = &fdi;
620 	struct fuse_dispatcher *fdip2 = NULL;
621 
622 	int err;
623 
624 	struct mount *mp = vnode_mount(dvp);
625 	data = fuse_get_mpdata(mp);
626 	uint64_t parentnid = VTOFUD(dvp)->nid;
627 	mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode);
628 	enum fuse_opcode op;
629 	int flags;
630 
631 	if (fuse_isdeadfs(dvp))
632 		return ENXIO;
633 
634 	/* FUSE expects sockets to be created with FUSE_MKNOD */
635 	if (vap->va_type == VSOCK)
636 		return fuse_internal_mknod(dvp, vpp, cnp, vap);
637 
638 	/*
639 	 * VOP_CREATE doesn't tell us the open(2) flags, so we guess.  Only a
640 	 * writable mode makes sense, and we might as well include readability
641 	 * too.
642 	 */
643 	flags = O_RDWR;
644 
645 	bzero(&fdi, sizeof(fdi));
646 
647 	if (vap->va_type != VREG)
648 		return (EINVAL);
649 
650 	if (!fsess_isimpl(mp, FUSE_CREATE) || vap->va_type == VSOCK) {
651 		/* Fallback to FUSE_MKNOD/FUSE_OPEN */
652 		fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
653 			cred, mode, &op);
654 	} else {
655 		/* Use FUSE_CREATE */
656 		size_t insize;
657 
658 		op = FUSE_CREATE;
659 		fdisp_init(fdip, sizeof(*fci) + cnp->cn_namelen + 1);
660 		fdisp_make(fdip, op, vnode_mount(dvp), parentnid, td, cred);
661 		fci = fdip->indata;
662 		fci->mode = mode;
663 		fci->flags = O_CREAT | flags;
664 		if (fuse_libabi_geq(data, 7, 12)) {
665 			insize = sizeof(*fci);
666 			fci->umask = td->td_proc->p_fd->fd_cmask;
667 		} else {
668 			insize = sizeof(struct fuse_open_in);
669 		}
670 
671 		memcpy((char *)fdip->indata + insize, cnp->cn_nameptr,
672 		    cnp->cn_namelen);
673 		((char *)fdip->indata)[insize + cnp->cn_namelen] = '\0';
674 	}
675 
676 	err = fdisp_wait_answ(fdip);
677 
678 	if (err) {
679 		if (err == ENOSYS && op == FUSE_CREATE) {
680 			fsess_set_notimpl(mp, FUSE_CREATE);
681 			fdisp_destroy(fdip);
682 			fdisp_make_mknod_for_fallback(fdip, cnp, dvp,
683 				parentnid, td, cred, mode, &op);
684 			err = fdisp_wait_answ(fdip);
685 		}
686 		if (err)
687 			goto out;
688 	}
689 
690 	feo = fdip->answ;
691 
692 	if ((err = fuse_internal_checkentry(feo, vap->va_type))) {
693 		goto out;
694 	}
695 
696 	if (op == FUSE_CREATE) {
697 		foo = (struct fuse_open_out*)(feo + 1);
698 	} else {
699 		/* Issue a separate FUSE_OPEN */
700 		struct fuse_open_in *foi;
701 
702 		fdip2 = &fdi2;
703 		fdisp_init(fdip2, sizeof(*foi));
704 		fdisp_make(fdip2, FUSE_OPEN, vnode_mount(dvp), feo->nodeid, td,
705 			cred);
706 		foi = fdip2->indata;
707 		foi->flags = flags;
708 		err = fdisp_wait_answ(fdip2);
709 		if (err)
710 			goto out;
711 		foo = fdip2->answ;
712 	}
713 	err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vap->va_type);
714 	if (err) {
715 		struct fuse_release_in *fri;
716 		uint64_t nodeid = feo->nodeid;
717 		uint64_t fh_id = foo->fh;
718 
719 		fdisp_init(fdip, sizeof(*fri));
720 		fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred);
721 		fri = fdip->indata;
722 		fri->fh = fh_id;
723 		fri->flags = flags;
724 		fuse_insert_callback(fdip->tick, fuse_internal_forget_callback);
725 		fuse_insert_message(fdip->tick, false);
726 		goto out;
727 	}
728 	ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
729 	fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid,
730 		feo->attr_valid_nsec, NULL);
731 
732 	fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, td, cred, foo);
733 	fuse_vnode_open(*vpp, foo->open_flags, td);
734 	/*
735 	 * Purge the parent's attribute cache because the daemon should've
736 	 * updated its mtime and ctime
737 	 */
738 	fuse_vnode_clear_attr_cache(dvp);
739 	cache_purge_negative(dvp);
740 
741 out:
742 	if (fdip2)
743 		fdisp_destroy(fdip2);
744 	fdisp_destroy(fdip);
745 	return err;
746 }
747 
748 /*
749     struct vnop_fdatasync_args {
750 	struct vop_generic_args a_gen;
751 	struct vnode * a_vp;
752 	struct thread * a_td;
753     };
754 */
755 static int
fuse_vnop_fdatasync(struct vop_fdatasync_args * ap)756 fuse_vnop_fdatasync(struct vop_fdatasync_args *ap)
757 {
758 	struct vnode *vp = ap->a_vp;
759 	struct thread *td = ap->a_td;
760 	int waitfor = MNT_WAIT;
761 
762 	int err = 0;
763 
764 	if (fuse_isdeadfs(vp)) {
765 		return 0;
766 	}
767 	if ((err = vop_stdfdatasync_buf(ap)))
768 		return err;
769 
770 	return fuse_internal_fsync(vp, td, waitfor, true);
771 }
772 
773 /*
774     struct vnop_fsync_args {
775 	struct vop_generic_args a_gen;
776 	struct vnode * a_vp;
777 	int  a_waitfor;
778 	struct thread * a_td;
779     };
780 */
781 static int
fuse_vnop_fsync(struct vop_fsync_args * ap)782 fuse_vnop_fsync(struct vop_fsync_args *ap)
783 {
784 	struct vnode *vp = ap->a_vp;
785 	struct thread *td = ap->a_td;
786 	int waitfor = ap->a_waitfor;
787 	int err = 0;
788 
789 	if (fuse_isdeadfs(vp)) {
790 		return 0;
791 	}
792 	if ((err = vop_stdfsync(ap)))
793 		return err;
794 
795 	return fuse_internal_fsync(vp, td, waitfor, false);
796 }
797 
798 /*
799     struct vnop_getattr_args {
800 	struct vnode *a_vp;
801 	struct vattr *a_vap;
802 	struct ucred *a_cred;
803 	struct thread *a_td;
804     };
805 */
806 static int
fuse_vnop_getattr(struct vop_getattr_args * ap)807 fuse_vnop_getattr(struct vop_getattr_args *ap)
808 {
809 	struct vnode *vp = ap->a_vp;
810 	struct vattr *vap = ap->a_vap;
811 	struct ucred *cred = ap->a_cred;
812 	struct thread *td = curthread;
813 
814 	int err = 0;
815 	int dataflags;
816 
817 	dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
818 
819 	/* Note that we are not bailing out on a dead file system just yet. */
820 
821 	if (!(dataflags & FSESS_INITED)) {
822 		if (!vnode_isvroot(vp)) {
823 			fdata_set_dead(fuse_get_mpdata(vnode_mount(vp)));
824 			err = ENOTCONN;
825 			return err;
826 		} else {
827 			goto fake;
828 		}
829 	}
830 	err = fuse_internal_getattr(vp, vap, cred, td);
831 	if (err == ENOTCONN && vnode_isvroot(vp)) {
832 		/* see comment in fuse_vfsop_statfs() */
833 		goto fake;
834 	} else {
835 		return err;
836 	}
837 
838 fake:
839 	bzero(vap, sizeof(*vap));
840 	vap->va_type = vnode_vtype(vp);
841 
842 	return 0;
843 }
844 
845 /*
846     struct vnop_inactive_args {
847 	struct vnode *a_vp;
848 	struct thread *a_td;
849     };
850 */
851 static int
fuse_vnop_inactive(struct vop_inactive_args * ap)852 fuse_vnop_inactive(struct vop_inactive_args *ap)
853 {
854 	struct vnode *vp = ap->a_vp;
855 	struct thread *td = ap->a_td;
856 
857 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
858 	struct fuse_filehandle *fufh, *fufh_tmp;
859 
860 	int need_flush = 1;
861 
862 	LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
863 		if (need_flush && vp->v_type == VREG) {
864 			if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
865 				fuse_vnode_savesize(vp, NULL, 0);
866 			}
867 			if ((fvdat->flag & FN_REVOKED) != 0)
868 				fuse_io_invalbuf(vp, td);
869 			else
870 				fuse_io_flushbuf(vp, MNT_WAIT, td);
871 			need_flush = 0;
872 		}
873 		fuse_filehandle_close(vp, fufh, td, NULL);
874 	}
875 
876 	if ((fvdat->flag & FN_REVOKED) != 0)
877 		vrecycle(vp);
878 
879 	return 0;
880 }
881 
882 /*
883     struct vnop_link_args {
884 	struct vnode *a_tdvp;
885 	struct vnode *a_vp;
886 	struct componentname *a_cnp;
887     };
888 */
889 static int
fuse_vnop_link(struct vop_link_args * ap)890 fuse_vnop_link(struct vop_link_args *ap)
891 {
892 	struct vnode *vp = ap->a_vp;
893 	struct vnode *tdvp = ap->a_tdvp;
894 	struct componentname *cnp = ap->a_cnp;
895 
896 	struct vattr *vap = VTOVA(vp);
897 
898 	struct fuse_dispatcher fdi;
899 	struct fuse_entry_out *feo;
900 	struct fuse_link_in fli;
901 
902 	int err;
903 
904 	if (fuse_isdeadfs(vp)) {
905 		return ENXIO;
906 	}
907 	if (vnode_mount(tdvp) != vnode_mount(vp)) {
908 		return EXDEV;
909 	}
910 
911 	/*
912 	 * This is a seatbelt check to protect naive userspace filesystems from
913 	 * themselves and the limitations of the FUSE IPC protocol.  If a
914 	 * filesystem does not allow attribute caching, assume it is capable of
915 	 * validating that nlink does not overflow.
916 	 */
917 	if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX)
918 		return EMLINK;
919 	fli.oldnodeid = VTOI(vp);
920 
921 	fdisp_init(&fdi, 0);
922 	fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp,
923 	    FUSE_LINK, &fli, sizeof(fli), &fdi);
924 	if ((err = fdisp_wait_answ(&fdi))) {
925 		goto out;
926 	}
927 	feo = fdi.answ;
928 
929 	err = fuse_internal_checkentry(feo, vnode_vtype(vp));
930 	if (!err) {
931 		/*
932 		 * Purge the parent's attribute cache because the daemon
933 		 * should've updated its mtime and ctime
934 		 */
935 		fuse_vnode_clear_attr_cache(tdvp);
936 		fuse_internal_cache_attrs(vp, &feo->attr, feo->attr_valid,
937 			feo->attr_valid_nsec, NULL);
938 	}
939 out:
940 	fdisp_destroy(&fdi);
941 	return err;
942 }
943 
944 struct fuse_lookup_alloc_arg {
945 	struct fuse_entry_out *feo;
946 	struct componentname *cnp;
947 	uint64_t nid;
948 	enum vtype vtyp;
949 };
950 
951 /* Callback for vn_get_ino */
952 static int
fuse_lookup_alloc(struct mount * mp,void * arg,int lkflags,struct vnode ** vpp)953 fuse_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp)
954 {
955 	struct fuse_lookup_alloc_arg *flaa = arg;
956 
957 	return fuse_vnode_get(mp, flaa->feo, flaa->nid, NULL, vpp, flaa->cnp,
958 		flaa->vtyp);
959 }
960 
961 SDT_PROBE_DEFINE3(fusefs, , vnops, cache_lookup,
962 	"int", "struct timespec*", "struct timespec*");
963 /*
964     struct vnop_lookup_args {
965 	struct vnodeop_desc *a_desc;
966 	struct vnode *a_dvp;
967 	struct vnode **a_vpp;
968 	struct componentname *a_cnp;
969     };
970 */
971 int
fuse_vnop_lookup(struct vop_lookup_args * ap)972 fuse_vnop_lookup(struct vop_lookup_args *ap)
973 {
974 	struct vnode *dvp = ap->a_dvp;
975 	struct vnode **vpp = ap->a_vpp;
976 	struct componentname *cnp = ap->a_cnp;
977 	struct thread *td = cnp->cn_thread;
978 	struct ucred *cred = cnp->cn_cred;
979 
980 	int nameiop = cnp->cn_nameiop;
981 	int flags = cnp->cn_flags;
982 	int wantparent = flags & (LOCKPARENT | WANTPARENT);
983 	int islastcn = flags & ISLASTCN;
984 	struct mount *mp = vnode_mount(dvp);
985 
986 	int err = 0;
987 	int lookup_err = 0;
988 	struct vnode *vp = NULL;
989 
990 	struct fuse_dispatcher fdi;
991 	bool did_lookup = false;
992 	struct fuse_entry_out *feo = NULL;
993 	enum vtype vtyp;	/* vnode type of target */
994 	off_t filesize;		/* filesize of target */
995 
996 	uint64_t nid;
997 
998 	if (fuse_isdeadfs(dvp)) {
999 		*vpp = NULL;
1000 		return ENXIO;
1001 	}
1002 	if (!vnode_isdir(dvp))
1003 		return ENOTDIR;
1004 
1005 	if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP))
1006 		return EROFS;
1007 
1008 	if ((err = fuse_internal_access(dvp, VEXEC, td, cred)))
1009 		return err;
1010 
1011 	if (flags & ISDOTDOT) {
1012 		KASSERT(VTOFUD(dvp)->flag & FN_PARENT_NID,
1013 			("Looking up .. is TODO"));
1014 		nid = VTOFUD(dvp)->parent_nid;
1015 		if (nid == 0)
1016 			return ENOENT;
1017 		/* .. is obviously a directory */
1018 		vtyp = VDIR;
1019 		filesize = 0;
1020 	} else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
1021 		nid = VTOI(dvp);
1022 		/* . is obviously a directory */
1023 		vtyp = VDIR;
1024 		filesize = 0;
1025 	} else {
1026 		struct timespec now, timeout;
1027 
1028 		err = cache_lookup(dvp, vpp, cnp, &timeout, NULL);
1029 		getnanouptime(&now);
1030 		SDT_PROBE3(fusefs, , vnops, cache_lookup, err, &timeout, &now);
1031 		switch (err) {
1032 		case -1:		/* positive match */
1033 			if (timespeccmp(&timeout, &now, >)) {
1034 				counter_u64_add(fuse_lookup_cache_hits, 1);
1035 			} else {
1036 				/* Cache timeout */
1037 				counter_u64_add(fuse_lookup_cache_misses, 1);
1038 				bintime_clear(
1039 					&VTOFUD(*vpp)->entry_cache_timeout);
1040 				cache_purge(*vpp);
1041 				if (dvp != *vpp)
1042 					vput(*vpp);
1043 				else
1044 					vrele(*vpp);
1045 				*vpp = NULL;
1046 				break;
1047 			}
1048 			return 0;
1049 
1050 		case 0:		/* no match in cache */
1051 			counter_u64_add(fuse_lookup_cache_misses, 1);
1052 			break;
1053 
1054 		case ENOENT:		/* negative match */
1055 			getnanouptime(&now);
1056 			if (timespeccmp(&timeout, &now, <=)) {
1057 				/* Cache timeout */
1058 				cache_purge_negative(dvp);
1059 				break;
1060 			}
1061 			/* fall through */
1062 		default:
1063 			return err;
1064 		}
1065 
1066 		nid = VTOI(dvp);
1067 		fdisp_init(&fdi, cnp->cn_namelen + 1);
1068 		fdisp_make(&fdi, FUSE_LOOKUP, mp, nid, td, cred);
1069 
1070 		memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1071 		((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1072 		lookup_err = fdisp_wait_answ(&fdi);
1073 		did_lookup = true;
1074 
1075 		if (!lookup_err) {
1076 			/* lookup call succeeded */
1077 			feo = (struct fuse_entry_out *)fdi.answ;
1078 			nid = feo->nodeid;
1079 			if (nid == 0) {
1080 				/* zero nodeid means ENOENT and cache it */
1081 				struct timespec timeout;
1082 
1083 				fdi.answ_stat = ENOENT;
1084 				lookup_err = ENOENT;
1085 				if (cnp->cn_flags & MAKEENTRY) {
1086 					fuse_validity_2_timespec(feo, &timeout);
1087 					cache_enter_time(dvp, *vpp, cnp,
1088 						&timeout, NULL);
1089 				}
1090 			} else if (nid == FUSE_ROOT_ID) {
1091 				lookup_err = EINVAL;
1092 			}
1093 			vtyp = IFTOVT(feo->attr.mode);
1094 			filesize = feo->attr.size;
1095 		}
1096 		if (lookup_err && (!fdi.answ_stat || lookup_err != ENOENT)) {
1097 			fdisp_destroy(&fdi);
1098 			return lookup_err;
1099 		}
1100 	}
1101 	/* lookup_err, if non-zero, must be ENOENT at this point */
1102 
1103 	if (lookup_err) {
1104 		/* Entry not found */
1105 		if ((nameiop == CREATE || nameiop == RENAME) && islastcn) {
1106 			err = fuse_internal_access(dvp, VWRITE, td, cred);
1107 			if (!err) {
1108 				/*
1109 				 * Set the SAVENAME flag to hold onto the
1110 				 * pathname for use later in VOP_CREATE or
1111 				 * VOP_RENAME.
1112 				 */
1113 				cnp->cn_flags |= SAVENAME;
1114 
1115 				err = EJUSTRETURN;
1116 			}
1117 		} else {
1118 			err = ENOENT;
1119 		}
1120 	} else {
1121 		/* Entry was found */
1122 		if (flags & ISDOTDOT) {
1123 			struct fuse_lookup_alloc_arg flaa;
1124 
1125 			flaa.nid = nid;
1126 			flaa.feo = feo;
1127 			flaa.cnp = cnp;
1128 			flaa.vtyp = vtyp;
1129 			err = vn_vget_ino_gen(dvp, fuse_lookup_alloc, &flaa, 0,
1130 				&vp);
1131 			*vpp = vp;
1132 		} else if (nid == VTOI(dvp)) {
1133 			vref(dvp);
1134 			*vpp = dvp;
1135 		} else {
1136 			struct fuse_vnode_data *fvdat;
1137 
1138 			err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
1139 			    &vp, cnp, vtyp);
1140 			if (err)
1141 				goto out;
1142 			*vpp = vp;
1143 
1144 			/*
1145 			 * In the case where we are looking up a FUSE node
1146 			 * represented by an existing cached vnode, and the
1147 			 * true size reported by FUSE_LOOKUP doesn't match
1148 			 * the vnode's cached size, then any cached writes
1149 			 * beyond the file's current size are lost.
1150 			 *
1151 			 * We can get here:
1152 			 * * following attribute cache expiration, or
1153 			 * * due a bug in the daemon, or
1154 			 */
1155 			fvdat = VTOFUD(vp);
1156 			if (vnode_isreg(vp) &&
1157 			    filesize != fvdat->cached_attrs.va_size &&
1158 			    fvdat->flag & FN_SIZECHANGE) {
1159 				/*
1160 				 * The FN_SIZECHANGE flag reflects a dirty
1161 				 * append.  If userspace lets us know our cache
1162 				 * is invalid, that write was lost.  (Dirty
1163 				 * writes that do not cause append are also
1164 				 * lost, but we don't detect them here.)
1165 				 *
1166 				 * XXX: Maybe disable WB caching on this mount.
1167 				 */
1168 				printf("%s: WB cache incoherent on %s!\n",
1169 				    __func__,
1170 				    vnode_mount(vp)->mnt_stat.f_mntonname);
1171 
1172 				fvdat->flag &= ~FN_SIZECHANGE;
1173 			}
1174 
1175 			MPASS(feo != NULL);
1176 			fuse_internal_cache_attrs(*vpp, &feo->attr,
1177 				feo->attr_valid, feo->attr_valid_nsec, NULL);
1178 			fuse_validity_2_bintime(feo->entry_valid,
1179 				feo->entry_valid_nsec,
1180 				&fvdat->entry_cache_timeout);
1181 
1182 			if ((nameiop == DELETE || nameiop == RENAME) &&
1183 				islastcn)
1184 			{
1185 				struct vattr dvattr;
1186 
1187 				err = fuse_internal_access(dvp, VWRITE, td,
1188 					cred);
1189 				if (err != 0)
1190 					goto out;
1191 				/*
1192 				 * if the parent's sticky bit is set, check
1193 				 * whether we're allowed to remove the file.
1194 				 * Need to figure out the vnode locking to make
1195 				 * this work.
1196 				 */
1197 				fuse_internal_getattr(dvp, &dvattr, cred, td);
1198 				if ((dvattr.va_mode & S_ISTXT) &&
1199 					fuse_internal_access(dvp, VADMIN, td,
1200 						cred) &&
1201 					fuse_internal_access(*vpp, VADMIN, td,
1202 						cred)) {
1203 					err = EPERM;
1204 					goto out;
1205 				}
1206 			}
1207 
1208 			if (islastcn && (
1209 				(nameiop == DELETE) ||
1210 				(nameiop == RENAME && wantparent))) {
1211 				cnp->cn_flags |= SAVENAME;
1212 			}
1213 
1214 		}
1215 	}
1216 out:
1217 	if (err) {
1218 		if (vp != NULL && dvp != vp)
1219 			vput(vp);
1220 		else if (vp != NULL)
1221 			vrele(vp);
1222 		*vpp = NULL;
1223 	}
1224 	if (did_lookup)
1225 		fdisp_destroy(&fdi);
1226 
1227 	return err;
1228 }
1229 
1230 /*
1231     struct vnop_mkdir_args {
1232 	struct vnode *a_dvp;
1233 	struct vnode **a_vpp;
1234 	struct componentname *a_cnp;
1235 	struct vattr *a_vap;
1236     };
1237 */
1238 static int
fuse_vnop_mkdir(struct vop_mkdir_args * ap)1239 fuse_vnop_mkdir(struct vop_mkdir_args *ap)
1240 {
1241 	struct vnode *dvp = ap->a_dvp;
1242 	struct vnode **vpp = ap->a_vpp;
1243 	struct componentname *cnp = ap->a_cnp;
1244 	struct vattr *vap = ap->a_vap;
1245 
1246 	struct fuse_mkdir_in fmdi;
1247 
1248 	if (fuse_isdeadfs(dvp)) {
1249 		return ENXIO;
1250 	}
1251 	fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
1252 	fmdi.umask = curthread->td_proc->p_fd->fd_cmask;
1253 
1254 	return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
1255 	    sizeof(fmdi), VDIR));
1256 }
1257 
1258 /*
1259     struct vnop_mknod_args {
1260 	struct vnode *a_dvp;
1261 	struct vnode **a_vpp;
1262 	struct componentname *a_cnp;
1263 	struct vattr *a_vap;
1264     };
1265 */
1266 static int
fuse_vnop_mknod(struct vop_mknod_args * ap)1267 fuse_vnop_mknod(struct vop_mknod_args *ap)
1268 {
1269 
1270 	struct vnode *dvp = ap->a_dvp;
1271 	struct vnode **vpp = ap->a_vpp;
1272 	struct componentname *cnp = ap->a_cnp;
1273 	struct vattr *vap = ap->a_vap;
1274 
1275 	if (fuse_isdeadfs(dvp))
1276 		return ENXIO;
1277 
1278 	return fuse_internal_mknod(dvp, vpp, cnp, vap);
1279 }
1280 
1281 /*
1282     struct vop_open_args {
1283 	struct vnode *a_vp;
1284 	int  a_mode;
1285 	struct ucred *a_cred;
1286 	struct thread *a_td;
1287 	int a_fdidx; / struct file *a_fp;
1288     };
1289 */
1290 static int
fuse_vnop_open(struct vop_open_args * ap)1291 fuse_vnop_open(struct vop_open_args *ap)
1292 {
1293 	struct vnode *vp = ap->a_vp;
1294 	int a_mode = ap->a_mode;
1295 	struct thread *td = ap->a_td;
1296 	struct ucred *cred = ap->a_cred;
1297 	pid_t pid = td->td_proc->p_pid;
1298 	struct fuse_vnode_data *fvdat;
1299 
1300 	if (fuse_isdeadfs(vp))
1301 		return ENXIO;
1302 	if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
1303 		return (EOPNOTSUPP);
1304 	if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0)
1305 		return EINVAL;
1306 
1307 	fvdat = VTOFUD(vp);
1308 
1309 	if (fuse_filehandle_validrw(vp, a_mode, cred, pid)) {
1310 		fuse_vnode_open(vp, 0, td);
1311 		return 0;
1312 	}
1313 
1314 	return fuse_filehandle_open(vp, a_mode, NULL, td, cred);
1315 }
1316 
1317 static int
fuse_vnop_pathconf(struct vop_pathconf_args * ap)1318 fuse_vnop_pathconf(struct vop_pathconf_args *ap)
1319 {
1320 
1321 	switch (ap->a_name) {
1322 	case _PC_FILESIZEBITS:
1323 		*ap->a_retval = 64;
1324 		return (0);
1325 	case _PC_NAME_MAX:
1326 		*ap->a_retval = NAME_MAX;
1327 		return (0);
1328 	case _PC_LINK_MAX:
1329 		*ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX);
1330 		return (0);
1331 	case _PC_SYMLINK_MAX:
1332 		*ap->a_retval = MAXPATHLEN;
1333 		return (0);
1334 	case _PC_NO_TRUNC:
1335 		*ap->a_retval = 1;
1336 		return (0);
1337 	default:
1338 		return (vop_stdpathconf(ap));
1339 	}
1340 }
1341 
1342 /*
1343     struct vnop_read_args {
1344 	struct vnode *a_vp;
1345 	struct uio *a_uio;
1346 	int  a_ioflag;
1347 	struct ucred *a_cred;
1348     };
1349 */
1350 static int
fuse_vnop_read(struct vop_read_args * ap)1351 fuse_vnop_read(struct vop_read_args *ap)
1352 {
1353 	struct vnode *vp = ap->a_vp;
1354 	struct uio *uio = ap->a_uio;
1355 	int ioflag = ap->a_ioflag;
1356 	struct ucred *cred = ap->a_cred;
1357 	pid_t pid = curthread->td_proc->p_pid;
1358 
1359 	if (fuse_isdeadfs(vp)) {
1360 		return ENXIO;
1361 	}
1362 
1363 	if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1364 		ioflag |= IO_DIRECT;
1365 	}
1366 
1367 	return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
1368 }
1369 
1370 /*
1371     struct vnop_readdir_args {
1372 	struct vnode *a_vp;
1373 	struct uio *a_uio;
1374 	struct ucred *a_cred;
1375 	int *a_eofflag;
1376 	int *a_ncookies;
1377 	u_long **a_cookies;
1378     };
1379 */
1380 static int
fuse_vnop_readdir(struct vop_readdir_args * ap)1381 fuse_vnop_readdir(struct vop_readdir_args *ap)
1382 {
1383 	struct vnode *vp = ap->a_vp;
1384 	struct uio *uio = ap->a_uio;
1385 	struct ucred *cred = ap->a_cred;
1386 	struct fuse_filehandle *fufh = NULL;
1387 	struct fuse_iov cookediov;
1388 	int err = 0;
1389 	u_long *cookies;
1390 	off_t startoff;
1391 	ssize_t tresid;
1392 	int ncookies;
1393 	bool closefufh = false;
1394 	pid_t pid = curthread->td_proc->p_pid;
1395 
1396 	if (ap->a_eofflag)
1397 		*ap->a_eofflag = 0;
1398 	if (fuse_isdeadfs(vp)) {
1399 		return ENXIO;
1400 	}
1401 	if (				/* XXXIP ((uio_iovcnt(uio) > 1)) || */
1402 	    (uio_resid(uio) < sizeof(struct dirent))) {
1403 		return EINVAL;
1404 	}
1405 
1406 	tresid = uio->uio_resid;
1407 	startoff = uio->uio_offset;
1408 	err = fuse_filehandle_get_dir(vp, &fufh, cred, pid);
1409 	if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
1410 		/*
1411 		 * nfsd will do VOP_READDIR without first doing VOP_OPEN.  We
1412 		 * must implicitly open the directory here
1413 		 */
1414 		err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
1415 		if (err == 0) {
1416 			/*
1417 			 * When a directory is opened, it must be read from
1418 			 * the beginning.  Hopefully, the "startoff" still
1419 			 * exists as an offset cookie for the directory.
1420 			 * If not, it will read the entire directory without
1421 			 * returning any entries and just return eof.
1422 			 */
1423 			uio->uio_offset = 0;
1424 		}
1425 		closefufh = true;
1426 	}
1427 	if (err)
1428 		return (err);
1429 	if (ap->a_ncookies != NULL) {
1430 		ncookies = uio->uio_resid /
1431 			(offsetof(struct dirent, d_name) + 4) + 1;
1432 		cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
1433 		*ap->a_ncookies = ncookies;
1434 		*ap->a_cookies = cookies;
1435 	} else {
1436 		ncookies = 0;
1437 		cookies = NULL;
1438 	}
1439 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
1440 	fiov_init(&cookediov, DIRCOOKEDSIZE);
1441 
1442 	err = fuse_internal_readdir(vp, uio, startoff, fufh, &cookediov,
1443 		&ncookies, cookies);
1444 
1445 	fiov_teardown(&cookediov);
1446 	if (closefufh)
1447 		fuse_filehandle_close(vp, fufh, curthread, cred);
1448 
1449 	if (ap->a_ncookies != NULL) {
1450 		if (err == 0) {
1451 			*ap->a_ncookies -= ncookies;
1452 		} else {
1453 			free(*ap->a_cookies, M_TEMP);
1454 			*ap->a_ncookies = 0;
1455 			*ap->a_cookies = NULL;
1456 		}
1457 	}
1458 	if (err == 0 && tresid == uio->uio_resid)
1459 		*ap->a_eofflag = 1;
1460 
1461 	return err;
1462 }
1463 
1464 /*
1465     struct vnop_readlink_args {
1466 	struct vnode *a_vp;
1467 	struct uio *a_uio;
1468 	struct ucred *a_cred;
1469     };
1470 */
1471 static int
fuse_vnop_readlink(struct vop_readlink_args * ap)1472 fuse_vnop_readlink(struct vop_readlink_args *ap)
1473 {
1474 	struct vnode *vp = ap->a_vp;
1475 	struct uio *uio = ap->a_uio;
1476 	struct ucred *cred = ap->a_cred;
1477 
1478 	struct fuse_dispatcher fdi;
1479 	int err;
1480 
1481 	if (fuse_isdeadfs(vp)) {
1482 		return ENXIO;
1483 	}
1484 	if (!vnode_islnk(vp)) {
1485 		return EINVAL;
1486 	}
1487 	fdisp_init(&fdi, 0);
1488 	err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred);
1489 	if (err) {
1490 		goto out;
1491 	}
1492 	if (((char *)fdi.answ)[0] == '/' &&
1493 	    fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) {
1494 		char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname;
1495 
1496 		err = uiomove(mpth, strlen(mpth), uio);
1497 	}
1498 	if (!err) {
1499 		err = uiomove(fdi.answ, fdi.iosize, uio);
1500 	}
1501 out:
1502 	fdisp_destroy(&fdi);
1503 	return err;
1504 }
1505 
1506 /*
1507     struct vnop_reclaim_args {
1508 	struct vnode *a_vp;
1509 	struct thread *a_td;
1510     };
1511 */
1512 static int
fuse_vnop_reclaim(struct vop_reclaim_args * ap)1513 fuse_vnop_reclaim(struct vop_reclaim_args *ap)
1514 {
1515 	struct vnode *vp = ap->a_vp;
1516 	struct thread *td = ap->a_td;
1517 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
1518 	struct fuse_filehandle *fufh, *fufh_tmp;
1519 
1520 	if (!fvdat) {
1521 		panic("FUSE: no vnode data during recycling");
1522 	}
1523 	LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
1524 		printf("FUSE: vnode being reclaimed with open fufh "
1525 			"(type=%#x)", fufh->fufh_type);
1526 		fuse_filehandle_close(vp, fufh, td, NULL);
1527 	}
1528 
1529 	if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) {
1530 		fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
1531 		    fvdat->nlookup);
1532 	}
1533 	fuse_vnode_setparent(vp, NULL);
1534 	cache_purge(vp);
1535 	vfs_hash_remove(vp);
1536 	vnode_destroy_vobject(vp);
1537 	fuse_vnode_destroy(vp);
1538 
1539 	return 0;
1540 }
1541 
1542 /*
1543     struct vnop_remove_args {
1544 	struct vnode *a_dvp;
1545 	struct vnode *a_vp;
1546 	struct componentname *a_cnp;
1547     };
1548 */
1549 static int
fuse_vnop_remove(struct vop_remove_args * ap)1550 fuse_vnop_remove(struct vop_remove_args *ap)
1551 {
1552 	struct vnode *dvp = ap->a_dvp;
1553 	struct vnode *vp = ap->a_vp;
1554 	struct componentname *cnp = ap->a_cnp;
1555 
1556 	int err;
1557 
1558 	if (fuse_isdeadfs(vp)) {
1559 		return ENXIO;
1560 	}
1561 	if (vnode_isdir(vp)) {
1562 		return EPERM;
1563 	}
1564 
1565 	err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
1566 
1567 	return err;
1568 }
1569 
1570 /*
1571     struct vnop_rename_args {
1572 	struct vnode *a_fdvp;
1573 	struct vnode *a_fvp;
1574 	struct componentname *a_fcnp;
1575 	struct vnode *a_tdvp;
1576 	struct vnode *a_tvp;
1577 	struct componentname *a_tcnp;
1578     };
1579 */
1580 static int
fuse_vnop_rename(struct vop_rename_args * ap)1581 fuse_vnop_rename(struct vop_rename_args *ap)
1582 {
1583 	struct vnode *fdvp = ap->a_fdvp;
1584 	struct vnode *fvp = ap->a_fvp;
1585 	struct componentname *fcnp = ap->a_fcnp;
1586 	struct vnode *tdvp = ap->a_tdvp;
1587 	struct vnode *tvp = ap->a_tvp;
1588 	struct componentname *tcnp = ap->a_tcnp;
1589 	struct fuse_data *data;
1590 	bool newparent = fdvp != tdvp;
1591 	bool isdir = fvp->v_type == VDIR;
1592 	int err = 0;
1593 
1594 	if (fuse_isdeadfs(fdvp)) {
1595 		return ENXIO;
1596 	}
1597 	if (fvp->v_mount != tdvp->v_mount ||
1598 	    (tvp && fvp->v_mount != tvp->v_mount)) {
1599 		SDT_PROBE2(fusefs, , vnops, trace, 1, "cross-device rename");
1600 		err = EXDEV;
1601 		goto out;
1602 	}
1603 	cache_purge(fvp);
1604 
1605 	/*
1606 	 * FUSE library is expected to check if target directory is not
1607 	 * under the source directory in the file system tree.
1608 	 * Linux performs this check at VFS level.
1609 	 */
1610 	/*
1611 	 * If source is a directory, and it will get a new parent, user must
1612 	 * have write permission to it, so ".." can be modified.
1613 	 */
1614 	data = fuse_get_mpdata(vnode_mount(tdvp));
1615 	if (data->dataflags & FSESS_DEFAULT_PERMISSIONS && isdir && newparent) {
1616 		err = fuse_internal_access(fvp, VWRITE,
1617 			tcnp->cn_thread, tcnp->cn_cred);
1618 		if (err)
1619 			goto out;
1620 	}
1621 	sx_xlock(&data->rename_lock);
1622 	err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp);
1623 	if (err == 0) {
1624 		if (tdvp != fdvp)
1625 			fuse_vnode_setparent(fvp, tdvp);
1626 		if (tvp != NULL)
1627 			fuse_vnode_setparent(tvp, NULL);
1628 	}
1629 	sx_unlock(&data->rename_lock);
1630 
1631 	if (tvp != NULL && tvp != fvp) {
1632 		cache_purge(tvp);
1633 	}
1634 	if (vnode_isdir(fvp)) {
1635 		if ((tvp != NULL) && vnode_isdir(tvp)) {
1636 			cache_purge(tdvp);
1637 		}
1638 		cache_purge(fdvp);
1639 	}
1640 out:
1641 	if (tdvp == tvp) {
1642 		vrele(tdvp);
1643 	} else {
1644 		vput(tdvp);
1645 	}
1646 	if (tvp != NULL) {
1647 		vput(tvp);
1648 	}
1649 	vrele(fdvp);
1650 	vrele(fvp);
1651 
1652 	return err;
1653 }
1654 
1655 /*
1656     struct vnop_rmdir_args {
1657 	    struct vnode *a_dvp;
1658 	    struct vnode *a_vp;
1659 	    struct componentname *a_cnp;
1660     } *ap;
1661 */
1662 static int
fuse_vnop_rmdir(struct vop_rmdir_args * ap)1663 fuse_vnop_rmdir(struct vop_rmdir_args *ap)
1664 {
1665 	struct vnode *dvp = ap->a_dvp;
1666 	struct vnode *vp = ap->a_vp;
1667 
1668 	int err;
1669 
1670 	if (fuse_isdeadfs(vp)) {
1671 		return ENXIO;
1672 	}
1673 	if (VTOFUD(vp) == VTOFUD(dvp)) {
1674 		return EINVAL;
1675 	}
1676 	err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
1677 
1678 	return err;
1679 }
1680 
1681 /*
1682     struct vnop_setattr_args {
1683 	struct vnode *a_vp;
1684 	struct vattr *a_vap;
1685 	struct ucred *a_cred;
1686 	struct thread *a_td;
1687     };
1688 */
1689 static int
fuse_vnop_setattr(struct vop_setattr_args * ap)1690 fuse_vnop_setattr(struct vop_setattr_args *ap)
1691 {
1692 	struct vnode *vp = ap->a_vp;
1693 	struct vattr *vap = ap->a_vap;
1694 	struct ucred *cred = ap->a_cred;
1695 	struct thread *td = curthread;
1696 	struct mount *mp;
1697 	struct fuse_data *data;
1698 	struct vattr old_va;
1699 	int dataflags;
1700 	int err = 0, err2;
1701 	accmode_t accmode = 0;
1702 	bool checkperm;
1703 	bool drop_suid = false;
1704 	gid_t cr_gid;
1705 
1706 	mp = vnode_mount(vp);
1707 	data = fuse_get_mpdata(mp);
1708 	dataflags = data->dataflags;
1709 	checkperm = dataflags & FSESS_DEFAULT_PERMISSIONS;
1710 	if (cred->cr_ngroups > 0)
1711 		cr_gid = cred->cr_groups[0];
1712 	else
1713 		cr_gid = 0;
1714 
1715 	if (fuse_isdeadfs(vp)) {
1716 		return ENXIO;
1717 	}
1718 
1719 	if (vap->va_uid != (uid_t)VNOVAL) {
1720 		if (checkperm) {
1721 			/* Only root may change a file's owner */
1722 			err = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
1723 			if (err) {
1724 				/* As a special case, allow the null chown */
1725 				err2 = fuse_internal_getattr(vp, &old_va, cred,
1726 					td);
1727 				if (err2)
1728 					return (err2);
1729 				if (vap->va_uid != old_va.va_uid)
1730 					return err;
1731 				else
1732 					accmode |= VADMIN;
1733 				drop_suid = true;
1734 			} else
1735 				accmode |= VADMIN;
1736 		} else
1737 			accmode |= VADMIN;
1738 	}
1739 	if (vap->va_gid != (gid_t)VNOVAL) {
1740 		if (checkperm && priv_check_cred(cred, PRIV_VFS_CHOWN, 0))
1741 			drop_suid = true;
1742 		if (checkperm && !groupmember(vap->va_gid, cred))
1743 		{
1744 			/*
1745 			 * Non-root users may only chgrp to one of their own
1746 			 * groups
1747 			 */
1748 			err = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
1749 			if (err) {
1750 				/* As a special case, allow the null chgrp */
1751 				err2 = fuse_internal_getattr(vp, &old_va, cred,
1752 					td);
1753 				if (err2)
1754 					return (err2);
1755 				if (vap->va_gid != old_va.va_gid)
1756 					return err;
1757 				accmode |= VADMIN;
1758 			} else
1759 				accmode |= VADMIN;
1760 		} else
1761 			accmode |= VADMIN;
1762 	}
1763 	if (vap->va_size != VNOVAL) {
1764 		switch (vp->v_type) {
1765 		case VDIR:
1766 			return (EISDIR);
1767 		case VLNK:
1768 		case VREG:
1769 			if (vfs_isrdonly(mp))
1770 				return (EROFS);
1771 			break;
1772 		default:
1773 			/*
1774 			 * According to POSIX, the result is unspecified
1775 			 * for file types other than regular files,
1776 			 * directories and shared memory objects.  We
1777 			 * don't support shared memory objects in the file
1778 			 * system, and have dubious support for truncating
1779 			 * symlinks.  Just ignore the request in other cases.
1780 			 */
1781 			return (0);
1782 		}
1783 		/* Don't set accmode.  Permission to trunc is checked upstack */
1784 	}
1785 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
1786 		if (vap->va_vaflags & VA_UTIMES_NULL)
1787 			accmode |= VWRITE;
1788 		else
1789 			accmode |= VADMIN;
1790 	}
1791 	if (drop_suid) {
1792 		if (vap->va_mode != (mode_t)VNOVAL)
1793 			vap->va_mode &= ~(S_ISUID | S_ISGID);
1794 		else {
1795 			err = fuse_internal_getattr(vp, &old_va, cred, td);
1796 			if (err)
1797 				return (err);
1798 			vap->va_mode = old_va.va_mode & ~(S_ISUID | S_ISGID);
1799 		}
1800 	}
1801 	if (vap->va_mode != (mode_t)VNOVAL) {
1802 		/* Only root may set the sticky bit on non-directories */
1803 		if (checkperm && vp->v_type != VDIR && (vap->va_mode & S_ISTXT)
1804 		    && priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
1805 			return EFTYPE;
1806 		if (checkperm && (vap->va_mode & S_ISGID)) {
1807 			err = fuse_internal_getattr(vp, &old_va, cred, td);
1808 			if (err)
1809 				return (err);
1810 			if (!groupmember(old_va.va_gid, cred)) {
1811 				err = priv_check_cred(cred, PRIV_VFS_SETGID, 0);
1812 				if (err)
1813 					return (err);
1814 			}
1815 		}
1816 		accmode |= VADMIN;
1817 	}
1818 
1819 	if (vfs_isrdonly(mp))
1820 		return EROFS;
1821 
1822 	err = fuse_internal_access(vp, accmode, td, cred);
1823 	if (err)
1824 		return err;
1825 	else
1826 		return fuse_internal_setattr(vp, vap, td, cred);
1827 }
1828 
1829 /*
1830     struct vnop_strategy_args {
1831 	struct vnode *a_vp;
1832 	struct buf *a_bp;
1833     };
1834 */
1835 static int
fuse_vnop_strategy(struct vop_strategy_args * ap)1836 fuse_vnop_strategy(struct vop_strategy_args *ap)
1837 {
1838 	struct vnode *vp = ap->a_vp;
1839 	struct buf *bp = ap->a_bp;
1840 
1841 	if (!vp || fuse_isdeadfs(vp)) {
1842 		bp->b_ioflags |= BIO_ERROR;
1843 		bp->b_error = ENXIO;
1844 		bufdone(bp);
1845 		return 0;
1846 	}
1847 
1848 	/*
1849 	 * VOP_STRATEGY always returns zero and signals error via bp->b_ioflags.
1850 	 * fuse_io_strategy sets bp's error fields
1851 	 */
1852 	(void)fuse_io_strategy(vp, bp);
1853 
1854 	return 0;
1855 }
1856 
1857 
1858 /*
1859     struct vnop_symlink_args {
1860 	struct vnode *a_dvp;
1861 	struct vnode **a_vpp;
1862 	struct componentname *a_cnp;
1863 	struct vattr *a_vap;
1864 	char *a_target;
1865     };
1866 */
1867 static int
fuse_vnop_symlink(struct vop_symlink_args * ap)1868 fuse_vnop_symlink(struct vop_symlink_args *ap)
1869 {
1870 	struct vnode *dvp = ap->a_dvp;
1871 	struct vnode **vpp = ap->a_vpp;
1872 	struct componentname *cnp = ap->a_cnp;
1873 	char *target = ap->a_target;
1874 
1875 	struct fuse_dispatcher fdi;
1876 
1877 	int err;
1878 	size_t len;
1879 
1880 	if (fuse_isdeadfs(dvp)) {
1881 		return ENXIO;
1882 	}
1883 	/*
1884 	 * Unlike the other creator type calls, here we have to create a message
1885 	 * where the name of the new entry comes first, and the data describing
1886 	 * the entry comes second.
1887 	 * Hence we can't rely on our handy fuse_internal_newentry() routine,
1888 	 * but put together the message manually and just call the core part.
1889 	 */
1890 
1891 	len = strlen(target) + 1;
1892 	fdisp_init(&fdi, len + cnp->cn_namelen + 1);
1893 	fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
1894 
1895 	memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1896 	((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1897 	memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
1898 
1899 	err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
1900 	fdisp_destroy(&fdi);
1901 	return err;
1902 }
1903 
1904 /*
1905     struct vnop_write_args {
1906 	struct vnode *a_vp;
1907 	struct uio *a_uio;
1908 	int  a_ioflag;
1909 	struct ucred *a_cred;
1910     };
1911 */
1912 static int
fuse_vnop_write(struct vop_write_args * ap)1913 fuse_vnop_write(struct vop_write_args *ap)
1914 {
1915 	struct vnode *vp = ap->a_vp;
1916 	struct uio *uio = ap->a_uio;
1917 	int ioflag = ap->a_ioflag;
1918 	struct ucred *cred = ap->a_cred;
1919 	pid_t pid = curthread->td_proc->p_pid;
1920 
1921 	if (fuse_isdeadfs(vp)) {
1922 		return ENXIO;
1923 	}
1924 
1925 	if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1926 		ioflag |= IO_DIRECT;
1927 	}
1928 
1929 	return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
1930 }
1931 
1932 static daddr_t
fuse_gbp_getblkno(struct vnode * vp,vm_ooffset_t off)1933 fuse_gbp_getblkno(struct vnode *vp, vm_ooffset_t off)
1934 {
1935 	const int biosize = fuse_iosize(vp);
1936 
1937 	return (off / biosize);
1938 }
1939 
1940 static int
fuse_gbp_getblksz(struct vnode * vp,daddr_t lbn)1941 fuse_gbp_getblksz(struct vnode *vp, daddr_t lbn)
1942 {
1943 	off_t filesize;
1944 	int blksz, err;
1945 	const int biosize = fuse_iosize(vp);
1946 
1947 	err = fuse_vnode_size(vp, &filesize, NULL, NULL);
1948 	KASSERT(err == 0, ("vfs_bio_getpages can't handle errors here"));
1949 	if (err)
1950 		return biosize;
1951 
1952 	if ((off_t)lbn * biosize >= filesize) {
1953 		blksz = 0;
1954 	} else if ((off_t)(lbn + 1) * biosize > filesize) {
1955 		blksz = filesize - (off_t)lbn *biosize;
1956 	} else {
1957 		blksz = biosize;
1958 	}
1959 	return (blksz);
1960 }
1961 
1962 /*
1963     struct vnop_getpages_args {
1964 	struct vnode *a_vp;
1965 	vm_page_t *a_m;
1966 	int a_count;
1967 	int a_reqpage;
1968     };
1969 */
1970 static int
fuse_vnop_getpages(struct vop_getpages_args * ap)1971 fuse_vnop_getpages(struct vop_getpages_args *ap)
1972 {
1973 	struct vnode *vp = ap->a_vp;
1974 
1975 	if (!fsess_opt_mmap(vnode_mount(vp))) {
1976 		SDT_PROBE2(fusefs, , vnops, trace, 1,
1977 			"called on non-cacheable vnode??\n");
1978 		return (VM_PAGER_ERROR);
1979 	}
1980 
1981 	return (vfs_bio_getpages(vp, ap->a_m, ap->a_count, ap->a_rbehind,
1982 	    ap->a_rahead, fuse_gbp_getblkno, fuse_gbp_getblksz));
1983 }
1984 
1985 static const char extattr_namespace_separator = '.';
1986 
1987 /*
1988     struct vop_getextattr_args {
1989 	struct vop_generic_args a_gen;
1990 	struct vnode *a_vp;
1991 	int a_attrnamespace;
1992 	const char *a_name;
1993 	struct uio *a_uio;
1994 	size_t *a_size;
1995 	struct ucred *a_cred;
1996 	struct thread *a_td;
1997     };
1998 */
1999 static int
fuse_vnop_getextattr(struct vop_getextattr_args * ap)2000 fuse_vnop_getextattr(struct vop_getextattr_args *ap)
2001 {
2002 	struct vnode *vp = ap->a_vp;
2003 	struct uio *uio = ap->a_uio;
2004 	struct fuse_dispatcher fdi;
2005 	struct fuse_getxattr_in *get_xattr_in;
2006 	struct fuse_getxattr_out *get_xattr_out;
2007 	struct mount *mp = vnode_mount(vp);
2008 	struct thread *td = ap->a_td;
2009 	struct ucred *cred = ap->a_cred;
2010 	char *prefix;
2011 	char *attr_str;
2012 	size_t len;
2013 	int err;
2014 
2015 	if (fuse_isdeadfs(vp))
2016 		return (ENXIO);
2017 
2018 	if (!fsess_isimpl(mp, FUSE_GETXATTR))
2019 		return EOPNOTSUPP;
2020 
2021 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
2022 	if (err)
2023 		return err;
2024 
2025 	/* Default to looking for user attributes. */
2026 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2027 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2028 	else
2029 		prefix = EXTATTR_NAMESPACE_USER_STRING;
2030 
2031 	len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2032 	    strlen(ap->a_name) + 1;
2033 
2034 	fdisp_init(&fdi, len + sizeof(*get_xattr_in));
2035 	fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
2036 
2037 	get_xattr_in = fdi.indata;
2038 	/*
2039 	 * Check to see whether we're querying the available size or
2040 	 * issuing the actual request.  If we pass in 0, we get back struct
2041 	 * fuse_getxattr_out.  If we pass in a non-zero size, we get back
2042 	 * that much data, without the struct fuse_getxattr_out header.
2043 	 */
2044 	if (uio == NULL)
2045 		get_xattr_in->size = 0;
2046 	else
2047 		get_xattr_in->size = uio->uio_resid;
2048 
2049 	attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
2050 	snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2051 	    ap->a_name);
2052 
2053 	err = fdisp_wait_answ(&fdi);
2054 	if (err != 0) {
2055 		if (err == ENOSYS) {
2056 			fsess_set_notimpl(mp, FUSE_GETXATTR);
2057 			err = EOPNOTSUPP;
2058 		}
2059 		goto out;
2060 	}
2061 
2062 	get_xattr_out = fdi.answ;
2063 
2064 	if (ap->a_size != NULL)
2065 		*ap->a_size = get_xattr_out->size;
2066 
2067 	if (uio != NULL)
2068 		err = uiomove(fdi.answ, fdi.iosize, uio);
2069 
2070 out:
2071 	fdisp_destroy(&fdi);
2072 	return (err);
2073 }
2074 
2075 /*
2076     struct vop_setextattr_args {
2077 	struct vop_generic_args a_gen;
2078 	struct vnode *a_vp;
2079 	int a_attrnamespace;
2080 	const char *a_name;
2081 	struct uio *a_uio;
2082 	struct ucred *a_cred;
2083 	struct thread *a_td;
2084     };
2085 */
2086 static int
fuse_vnop_setextattr(struct vop_setextattr_args * ap)2087 fuse_vnop_setextattr(struct vop_setextattr_args *ap)
2088 {
2089 	struct vnode *vp = ap->a_vp;
2090 	struct uio *uio = ap->a_uio;
2091 	struct fuse_dispatcher fdi;
2092 	struct fuse_setxattr_in *set_xattr_in;
2093 	struct mount *mp = vnode_mount(vp);
2094 	struct thread *td = ap->a_td;
2095 	struct ucred *cred = ap->a_cred;
2096 	char *prefix;
2097 	size_t len;
2098 	char *attr_str;
2099 	int err;
2100 
2101 	if (fuse_isdeadfs(vp))
2102 		return (ENXIO);
2103 
2104 	if (!fsess_isimpl(mp, FUSE_SETXATTR))
2105 		return EOPNOTSUPP;
2106 
2107 	if (vfs_isrdonly(mp))
2108 		return EROFS;
2109 
2110 	/* Deleting xattrs must use VOP_DELETEEXTATTR instead */
2111 	if (ap->a_uio == NULL) {
2112 		/*
2113 		 * If we got here as fallback from VOP_DELETEEXTATTR, then
2114 		 * return EOPNOTSUPP.
2115 		 */
2116 		if (!fsess_isimpl(mp, FUSE_REMOVEXATTR))
2117 			return (EOPNOTSUPP);
2118 		else
2119 			return (EINVAL);
2120 	}
2121 
2122 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
2123 		VWRITE);
2124 	if (err)
2125 		return err;
2126 
2127 	/* Default to looking for user attributes. */
2128 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2129 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2130 	else
2131 		prefix = EXTATTR_NAMESPACE_USER_STRING;
2132 
2133 	len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2134 	    strlen(ap->a_name) + 1;
2135 
2136 	fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
2137 	fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
2138 
2139 	set_xattr_in = fdi.indata;
2140 	set_xattr_in->size = uio->uio_resid;
2141 
2142 	attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
2143 	snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2144 	    ap->a_name);
2145 
2146 	err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
2147 	    uio->uio_resid, uio);
2148 	if (err != 0) {
2149 		goto out;
2150 	}
2151 
2152 	err = fdisp_wait_answ(&fdi);
2153 
2154 	if (err == ENOSYS) {
2155 		fsess_set_notimpl(mp, FUSE_SETXATTR);
2156 		err = EOPNOTSUPP;
2157 	}
2158 	if (err == ERESTART) {
2159 		/* Can't restart after calling uiomove */
2160 		err = EINTR;
2161 	}
2162 
2163 out:
2164 	fdisp_destroy(&fdi);
2165 	return (err);
2166 }
2167 
2168 /*
2169  * The Linux / FUSE extended attribute list is simply a collection of
2170  * NUL-terminated strings.  The FreeBSD extended attribute list is a single
2171  * byte length followed by a non-NUL terminated string.  So, this allows
2172  * conversion of the Linux / FUSE format to the FreeBSD format in place.
2173  * Linux attribute names are reported with the namespace as a prefix (e.g.
2174  * "user.attribute_name"), but in FreeBSD they are reported without the
2175  * namespace prefix (e.g. "attribute_name").  So, we're going from:
2176  *
2177  * user.attr_name1\0user.attr_name2\0
2178  *
2179  * to:
2180  *
2181  * <num>attr_name1<num>attr_name2
2182  *
2183  * Where "<num>" is a single byte number of characters in the attribute name.
2184  *
2185  * Args:
2186  * prefix - exattr namespace prefix string
2187  * list, list_len - input list with namespace prefixes
2188  * bsd_list, bsd_list_len - output list compatible with bsd vfs
2189  */
2190 static int
fuse_xattrlist_convert(char * prefix,const char * list,int list_len,char * bsd_list,int * bsd_list_len)2191 fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
2192     char *bsd_list, int *bsd_list_len)
2193 {
2194 	int len, pos, dist_to_next, prefix_len;
2195 
2196 	pos = 0;
2197 	*bsd_list_len = 0;
2198 	prefix_len = strlen(prefix);
2199 
2200 	while (pos < list_len && list[pos] != '\0') {
2201 		dist_to_next = strlen(&list[pos]) + 1;
2202 		if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
2203 		    list[pos + prefix_len] == extattr_namespace_separator) {
2204 			len = dist_to_next -
2205 			    (prefix_len + sizeof(extattr_namespace_separator)) - 1;
2206 			if (len >= EXTATTR_MAXNAMELEN)
2207 				return (ENAMETOOLONG);
2208 
2209 			bsd_list[*bsd_list_len] = len;
2210 			memcpy(&bsd_list[*bsd_list_len + 1],
2211 			    &list[pos + prefix_len +
2212 			    sizeof(extattr_namespace_separator)], len);
2213 
2214 			*bsd_list_len += len + 1;
2215 		}
2216 
2217 		pos += dist_to_next;
2218 	}
2219 
2220 	return (0);
2221 }
2222 
2223 /*
2224  * List extended attributes
2225  *
2226  * The FUSE_LISTXATTR operation is based on Linux's listxattr(2) syscall, which
2227  * has a number of differences compared to its FreeBSD equivalent,
2228  * extattr_list_file:
2229  *
2230  * - FUSE_LISTXATTR returns all extended attributes across all namespaces,
2231  *   whereas listxattr(2) only returns attributes for a single namespace
2232  * - FUSE_LISTXATTR prepends each attribute name with "namespace."
2233  * - If the provided buffer is not large enough to hold the result,
2234  *   FUSE_LISTXATTR should return ERANGE, whereas listxattr is expected to
2235  *   return as many results as will fit.
2236  */
2237 /*
2238     struct vop_listextattr_args {
2239 	struct vop_generic_args a_gen;
2240 	struct vnode *a_vp;
2241 	int a_attrnamespace;
2242 	struct uio *a_uio;
2243 	size_t *a_size;
2244 	struct ucred *a_cred;
2245 	struct thread *a_td;
2246     };
2247 */
2248 static int
fuse_vnop_listextattr(struct vop_listextattr_args * ap)2249 fuse_vnop_listextattr(struct vop_listextattr_args *ap)
2250 {
2251 	struct vnode *vp = ap->a_vp;
2252 	struct uio *uio = ap->a_uio;
2253 	struct fuse_dispatcher fdi;
2254 	struct fuse_listxattr_in *list_xattr_in;
2255 	struct fuse_listxattr_out *list_xattr_out;
2256 	struct mount *mp = vnode_mount(vp);
2257 	struct thread *td = ap->a_td;
2258 	struct ucred *cred = ap->a_cred;
2259 	char *prefix;
2260 	char *bsd_list = NULL;
2261 	char *linux_list;
2262 	int bsd_list_len;
2263 	int linux_list_len;
2264 	int err;
2265 
2266 	if (fuse_isdeadfs(vp))
2267 		return (ENXIO);
2268 
2269 	if (!fsess_isimpl(mp, FUSE_LISTXATTR))
2270 		return EOPNOTSUPP;
2271 
2272 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
2273 	if (err)
2274 		return err;
2275 
2276 	/*
2277 	 * Add space for a NUL and the period separator if enabled.
2278 	 * Default to looking for user attributes.
2279 	 */
2280 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2281 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2282 	else
2283 		prefix = EXTATTR_NAMESPACE_USER_STRING;
2284 
2285 	fdisp_init(&fdi, sizeof(*list_xattr_in));
2286 	fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2287 
2288 	/*
2289 	 * Retrieve Linux / FUSE compatible list size.
2290 	 */
2291 	list_xattr_in = fdi.indata;
2292 	list_xattr_in->size = 0;
2293 
2294 	err = fdisp_wait_answ(&fdi);
2295 	if (err != 0) {
2296 		if (err == ENOSYS) {
2297 			fsess_set_notimpl(mp, FUSE_LISTXATTR);
2298 			err = EOPNOTSUPP;
2299 		}
2300 		goto out;
2301 	}
2302 
2303 	list_xattr_out = fdi.answ;
2304 	linux_list_len = list_xattr_out->size;
2305 	if (linux_list_len == 0) {
2306 		if (ap->a_size != NULL)
2307 			*ap->a_size = linux_list_len;
2308 		goto out;
2309 	}
2310 
2311 	/*
2312 	 * Retrieve Linux / FUSE compatible list values.
2313 	 */
2314 	fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2315 	list_xattr_in = fdi.indata;
2316 	list_xattr_in->size = linux_list_len;
2317 
2318 	err = fdisp_wait_answ(&fdi);
2319 	if (err == ERANGE) {
2320 		/*
2321 		 * Race detected.  The attribute list must've grown since the
2322 		 * first FUSE_LISTXATTR call.  Start over.  Go all the way back
2323 		 * to userland so we can process signals, if necessary, before
2324 		 * restarting.
2325 		 */
2326 		err = ERESTART;
2327 		goto out;
2328 	} else if (err != 0)
2329 		goto out;
2330 
2331 	linux_list = fdi.answ;
2332 	/* FUSE doesn't allow the server to return more data than requested */
2333 	if (fdi.iosize > linux_list_len) {
2334 		printf("WARNING: FUSE protocol violation.  Server returned "
2335 			"more extended attribute data than requested; "
2336 			"should've returned ERANGE instead");
2337 	} else {
2338 		/* But returning less data is fine */
2339 		linux_list_len = fdi.iosize;
2340 	}
2341 
2342 	/*
2343 	 * Retrieve the BSD compatible list values.
2344 	 * The Linux / FUSE attribute list format isn't the same
2345 	 * as FreeBSD's format. So we need to transform it into
2346 	 * FreeBSD's format before giving it to the user.
2347 	 */
2348 	bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
2349 	err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
2350 	    bsd_list, &bsd_list_len);
2351 	if (err != 0)
2352 		goto out;
2353 
2354 	if (ap->a_size != NULL)
2355 		*ap->a_size = bsd_list_len;
2356 
2357 	if (uio != NULL)
2358 		err = uiomove(bsd_list, bsd_list_len, uio);
2359 
2360 out:
2361 	free(bsd_list, M_TEMP);
2362 	fdisp_destroy(&fdi);
2363 	return (err);
2364 }
2365 
2366 /*
2367     struct vop_deleteextattr_args {
2368 	struct vop_generic_args a_gen;
2369 	struct vnode *a_vp;
2370 	int a_attrnamespace;
2371 	const char *a_name;
2372 	struct ucred *a_cred;
2373 	struct thread *a_td;
2374     };
2375 */
2376 static int
fuse_vnop_deleteextattr(struct vop_deleteextattr_args * ap)2377 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
2378 {
2379 	struct vnode *vp = ap->a_vp;
2380 	struct fuse_dispatcher fdi;
2381 	struct mount *mp = vnode_mount(vp);
2382 	struct thread *td = ap->a_td;
2383 	struct ucred *cred = ap->a_cred;
2384 	char *prefix;
2385 	size_t len;
2386 	char *attr_str;
2387 	int err;
2388 
2389 	if (fuse_isdeadfs(vp))
2390 		return (ENXIO);
2391 
2392 	if (!fsess_isimpl(mp, FUSE_REMOVEXATTR))
2393 		return EOPNOTSUPP;
2394 
2395 	if (vfs_isrdonly(mp))
2396 		return EROFS;
2397 
2398 	err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
2399 		VWRITE);
2400 	if (err)
2401 		return err;
2402 
2403 	/* Default to looking for user attributes. */
2404 	if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2405 		prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2406 	else
2407 		prefix = EXTATTR_NAMESPACE_USER_STRING;
2408 
2409 	len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2410 	    strlen(ap->a_name) + 1;
2411 
2412 	fdisp_init(&fdi, len);
2413 	fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
2414 
2415 	attr_str = fdi.indata;
2416 	snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2417 	    ap->a_name);
2418 
2419 	err = fdisp_wait_answ(&fdi);
2420 	if (err == ENOSYS) {
2421 		fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
2422 		err = EOPNOTSUPP;
2423 	}
2424 
2425 	fdisp_destroy(&fdi);
2426 	return (err);
2427 }
2428 
2429 /*
2430     struct vnop_print_args {
2431 	struct vnode *a_vp;
2432     };
2433 */
2434 static int
fuse_vnop_print(struct vop_print_args * ap)2435 fuse_vnop_print(struct vop_print_args *ap)
2436 {
2437 	struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
2438 
2439 	printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
2440 	    (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
2441 	    (uintmax_t)fvdat->nlookup,
2442 	    fvdat->flag);
2443 
2444 	return 0;
2445 }
2446 
2447 /*
2448  * Get an NFS filehandle for a FUSE file.
2449  *
2450  * This will only work for FUSE file systems that guarantee the uniqueness of
2451  * nodeid:generation, which most don't.
2452  */
2453 /*
2454 vop_vptofh {
2455 	IN struct vnode *a_vp;
2456 	IN struct fid *a_fhp;
2457 };
2458 */
2459 static int
fuse_vnop_vptofh(struct vop_vptofh_args * ap)2460 fuse_vnop_vptofh(struct vop_vptofh_args *ap)
2461 {
2462 	struct vnode *vp = ap->a_vp;
2463 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
2464 	struct fuse_fid *fhp = (struct fuse_fid *)(ap->a_fhp);
2465 	_Static_assert(sizeof(struct fuse_fid) <= sizeof(struct fid),
2466 		"FUSE fid type is too big");
2467 	struct mount *mp = vnode_mount(vp);
2468 	struct fuse_data *data = fuse_get_mpdata(mp);
2469 	struct vattr va;
2470 	int err;
2471 
2472 	if (!(data->dataflags & FSESS_EXPORT_SUPPORT))
2473 		return EOPNOTSUPP;
2474 
2475 	err = fuse_internal_getattr(vp, &va, curthread->td_ucred, curthread);
2476 	if (err)
2477 		return err;
2478 
2479 	/*ip = VTOI(ap->a_vp);*/
2480 	/*ufhp = (struct ufid *)ap->a_fhp;*/
2481 	fhp->len = sizeof(struct fuse_fid);
2482 	fhp->nid = fvdat->nid;
2483 	if (fvdat->generation <= UINT32_MAX)
2484 		fhp->gen = fvdat->generation;
2485 	else
2486 		return EOVERFLOW;
2487 	return (0);
2488 }
2489 
2490 
2491