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