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 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 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 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 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 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 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 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 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 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 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 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; 799 struct fuse_vnode_data *fvdat = VTOFUD(vp); 800 pid_t pid; 801 int err = 0; 802 803 /* NB: a_td will be NULL from some async kernel contexts */ 804 td = ap->a_td ? ap->a_td : curthread; 805 pid = td->td_proc->p_pid; 806 807 if (fuse_isdeadfs(vp)) 808 return 0; 809 if (vnode_isdir(vp)) 810 return 0; 811 if (fflag & IO_NDELAY) 812 return 0; 813 814 if (cred == NULL) 815 cred = td->td_ucred; 816 817 err = fuse_flush(vp, cred, pid, fflag); 818 if (err == 0 && (fvdat->flag & FN_ATIMECHANGE) && !vfs_isrdonly(mp)) { 819 struct vattr vap; 820 struct fuse_data *data; 821 int dataflags; 822 int access_e = 0; 823 824 data = fuse_get_mpdata(mp); 825 dataflags = data->dataflags; 826 if (dataflags & FSESS_DEFAULT_PERMISSIONS) { 827 struct vattr va; 828 829 fuse_internal_getattr(vp, &va, cred, td); 830 access_e = vaccess(vp->v_type, va.va_mode, va.va_uid, 831 va.va_gid, VWRITE, cred); 832 } 833 if (access_e == 0) { 834 VATTR_NULL(&vap); 835 vap.va_atime = fvdat->cached_attrs.va_atime; 836 /* 837 * Ignore errors setting when setting atime. That 838 * should not cause close(2) to fail. 839 */ 840 fuse_internal_setattr(vp, &vap, td, NULL); 841 } 842 } 843 /* TODO: close the file handle, if we're sure it's no longer used */ 844 if ((fvdat->flag & FN_SIZECHANGE) != 0) { 845 fuse_vnode_savesize(vp, cred, pid); 846 } 847 return err; 848 } 849 850 /* 851 struct vop_copy_file_range_args { 852 struct vop_generic_args a_gen; 853 struct vnode *a_invp; 854 off_t *a_inoffp; 855 struct vnode *a_outvp; 856 off_t *a_outoffp; 857 size_t *a_lenp; 858 unsigned int a_flags; 859 struct ucred *a_incred; 860 struct ucred *a_outcred; 861 struct thread *a_fsizetd; 862 } 863 */ 864 static int 865 fuse_vnop_copy_file_range(struct vop_copy_file_range_args *ap) 866 { 867 struct vnode *invp = ap->a_invp; 868 struct vnode *outvp = ap->a_outvp; 869 struct mount *mp = vnode_mount(invp); 870 struct fuse_vnode_data *outfvdat = VTOFUD(outvp); 871 struct fuse_dispatcher fdi; 872 struct fuse_filehandle *infufh, *outfufh; 873 struct fuse_copy_file_range_in *fcfri; 874 struct ucred *incred = ap->a_incred; 875 struct ucred *outcred = ap->a_outcred; 876 struct fuse_write_out *fwo; 877 struct thread *td; 878 struct uio io; 879 off_t outfilesize; 880 ssize_t r = 0; 881 pid_t pid; 882 int err; 883 884 if ((ap->a_flags & COPY_FILE_RANGE_CLONE) != 0) 885 return (EXTERROR(ENOSYS, "Cannot clone")); 886 887 if (mp == NULL || mp != vnode_mount(outvp)) 888 return (EXTERROR(ENOSYS, "Mount points do not match")); 889 890 if (incred->cr_uid != outcred->cr_uid) 891 return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not " 892 "support different credentials for infd and outfd")); 893 894 if (incred->cr_gid != outcred->cr_gid) 895 return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not " 896 "support different credentials for infd and outfd")); 897 898 /* Caller busied mp, mnt_data can be safely accessed. */ 899 if (fsess_not_impl(mp, FUSE_COPY_FILE_RANGE)) 900 return (EXTERROR(ENOSYS, "This daemon does not " 901 "implement COPY_FILE_RANGE")); 902 903 if (ap->a_fsizetd == NULL) 904 td = curthread; 905 else 906 td = ap->a_fsizetd; 907 pid = td->td_proc->p_pid; 908 909 vn_lock_pair(invp, false, LK_SHARED, outvp, false, LK_EXCLUSIVE); 910 if (invp->v_data == NULL || outvp->v_data == NULL) { 911 err = EXTERROR(EBADF, "vnode got reclaimed"); 912 goto unlock; 913 } 914 915 err = fuse_filehandle_getrw(invp, FREAD, &infufh, incred, pid); 916 if (err) 917 goto unlock; 918 919 err = fuse_filehandle_getrw(outvp, FWRITE, &outfufh, outcred, pid); 920 if (err) 921 goto unlock; 922 923 io.uio_resid = *ap->a_lenp; 924 if (ap->a_fsizetd) { 925 io.uio_offset = *ap->a_outoffp; 926 err = vn_rlimit_fsizex(outvp, &io, 0, &r, ap->a_fsizetd); 927 if (err != 0) 928 goto unlock; 929 } 930 931 err = fuse_vnode_size(outvp, &outfilesize, outcred, curthread); 932 if (err) 933 goto unlock; 934 935 vnode_pager_clean_sync(invp); 936 err = fuse_inval_buf_range(outvp, outfilesize, *ap->a_outoffp, 937 *ap->a_outoffp + io.uio_resid); 938 if (err) 939 goto unlock; 940 941 fdisp_init(&fdi, sizeof(*fcfri)); 942 fdisp_make_vp(&fdi, FUSE_COPY_FILE_RANGE, invp, td, incred); 943 fcfri = fdi.indata; 944 fcfri->fh_in = infufh->fh_id; 945 fcfri->off_in = *ap->a_inoffp; 946 fcfri->nodeid_out = VTOI(outvp); 947 fcfri->fh_out = outfufh->fh_id; 948 fcfri->off_out = *ap->a_outoffp; 949 fcfri->len = io.uio_resid; 950 fcfri->flags = 0; 951 952 err = fdisp_wait_answ(&fdi); 953 if (err == 0) { 954 fwo = fdi.answ; 955 *ap->a_lenp = fwo->size; 956 *ap->a_inoffp += fwo->size; 957 *ap->a_outoffp += fwo->size; 958 fuse_internal_clear_suid_on_write(outvp, outcred, td); 959 if (*ap->a_outoffp > outfvdat->cached_attrs.va_size) { 960 fuse_vnode_setsize(outvp, *ap->a_outoffp, false); 961 getnanouptime(&outfvdat->last_local_modify); 962 } 963 fuse_vnode_update(invp, FN_ATIMECHANGE); 964 fuse_vnode_update(outvp, FN_MTIMECHANGE | FN_CTIMECHANGE); 965 } 966 fdisp_destroy(&fdi); 967 968 unlock: 969 if (invp != outvp) 970 VOP_UNLOCK(invp); 971 VOP_UNLOCK(outvp); 972 973 if (err == ENOSYS) 974 fsess_set_notimpl(mp, FUSE_COPY_FILE_RANGE); 975 976 /* 977 * No need to call vn_rlimit_fsizex_res before return, since the uio is 978 * local. 979 */ 980 return (err); 981 } 982 983 static void 984 fdisp_make_mknod_for_fallback( 985 struct fuse_dispatcher *fdip, 986 struct componentname *cnp, 987 struct vnode *dvp, 988 uint64_t parentnid, 989 struct thread *td, 990 struct ucred *cred, 991 mode_t mode, 992 enum fuse_opcode *op) 993 { 994 struct fuse_mknod_in *fmni; 995 996 fdisp_init(fdip, sizeof(*fmni) + cnp->cn_namelen + 1); 997 *op = FUSE_MKNOD; 998 fdisp_make(fdip, *op, vnode_mount(dvp), parentnid, td, cred); 999 fmni = fdip->indata; 1000 fmni->mode = mode; 1001 fmni->rdev = 0; 1002 memcpy((char *)fdip->indata + sizeof(*fmni), cnp->cn_nameptr, 1003 cnp->cn_namelen); 1004 ((char *)fdip->indata)[sizeof(*fmni) + cnp->cn_namelen] = '\0'; 1005 } 1006 /* 1007 struct vnop_create_args { 1008 struct vnode *a_dvp; 1009 struct vnode **a_vpp; 1010 struct componentname *a_cnp; 1011 struct vattr *a_vap; 1012 }; 1013 */ 1014 static int 1015 fuse_vnop_create(struct vop_create_args *ap) 1016 { 1017 struct vnode *dvp = ap->a_dvp; 1018 struct vnode **vpp = ap->a_vpp; 1019 struct componentname *cnp = ap->a_cnp; 1020 struct vattr *vap = ap->a_vap; 1021 struct thread *td = curthread; 1022 struct ucred *cred = cnp->cn_cred; 1023 1024 struct fuse_data *data; 1025 struct fuse_create_in *fci; 1026 struct fuse_entry_out *feo; 1027 struct fuse_open_out *foo; 1028 struct fuse_dispatcher fdi, fdi2; 1029 struct fuse_dispatcher *fdip = &fdi; 1030 struct fuse_dispatcher *fdip2 = NULL; 1031 1032 int err; 1033 1034 struct mount *mp = vnode_mount(dvp); 1035 data = fuse_get_mpdata(mp); 1036 uint64_t parentnid = VTOFUD(dvp)->nid; 1037 mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode); 1038 enum fuse_opcode op; 1039 int flags; 1040 1041 if (fuse_isdeadfs(dvp)) 1042 return (EXTERROR(ENXIO, "This FUSE session is about " 1043 "to be closed")); 1044 1045 /* FUSE expects sockets to be created with FUSE_MKNOD */ 1046 if (vap->va_type == VSOCK) 1047 return fuse_internal_mknod(dvp, vpp, cnp, vap); 1048 1049 /* 1050 * VOP_CREATE doesn't tell us the open(2) flags, so we guess. Only a 1051 * writable mode makes sense, and we might as well include readability 1052 * too. 1053 */ 1054 flags = O_RDWR; 1055 1056 bzero(&fdi, sizeof(fdi)); 1057 1058 if (vap->va_type != VREG) 1059 return (EXTERROR(EINVAL, "Only regular files can be created")); 1060 1061 if (fsess_not_impl(mp, FUSE_CREATE) || vap->va_type == VSOCK) { 1062 /* Fallback to FUSE_MKNOD/FUSE_OPEN */ 1063 fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td, 1064 cred, mode, &op); 1065 } else { 1066 /* Use FUSE_CREATE */ 1067 size_t insize; 1068 1069 op = FUSE_CREATE; 1070 fdisp_init(fdip, sizeof(*fci) + cnp->cn_namelen + 1); 1071 fdisp_make(fdip, op, vnode_mount(dvp), parentnid, td, cred); 1072 fci = fdip->indata; 1073 fci->mode = mode; 1074 fci->flags = O_CREAT | flags; 1075 if (fuse_libabi_geq(data, 7, 12)) { 1076 insize = sizeof(*fci); 1077 fci->umask = td->td_proc->p_pd->pd_cmask; 1078 } else { 1079 insize = sizeof(struct fuse_open_in); 1080 } 1081 1082 memcpy((char *)fdip->indata + insize, cnp->cn_nameptr, 1083 cnp->cn_namelen); 1084 ((char *)fdip->indata)[insize + cnp->cn_namelen] = '\0'; 1085 } 1086 1087 err = fdisp_wait_answ(fdip); 1088 1089 if (err) { 1090 if (err == ENOSYS && op == FUSE_CREATE) { 1091 fsess_set_notimpl(mp, FUSE_CREATE); 1092 fdisp_destroy(fdip); 1093 fdisp_make_mknod_for_fallback(fdip, cnp, dvp, 1094 parentnid, td, cred, mode, &op); 1095 err = fdisp_wait_answ(fdip); 1096 } 1097 if (err) 1098 goto out; 1099 } 1100 1101 feo = fdip->answ; 1102 1103 if ((err = fuse_internal_checkentry(feo, vap->va_type))) { 1104 goto out; 1105 } 1106 1107 if (op == FUSE_CREATE) { 1108 if (fuse_libabi_geq(data, 7, 9)) 1109 foo = (struct fuse_open_out*)(feo + 1); 1110 else 1111 foo = (struct fuse_open_out*)((char*)feo + 1112 FUSE_COMPAT_ENTRY_OUT_SIZE); 1113 } else { 1114 /* Issue a separate FUSE_OPEN */ 1115 struct fuse_open_in *foi; 1116 1117 fdip2 = &fdi2; 1118 fdisp_init(fdip2, sizeof(*foi)); 1119 fdisp_make(fdip2, FUSE_OPEN, vnode_mount(dvp), feo->nodeid, td, 1120 cred); 1121 foi = fdip2->indata; 1122 foi->flags = flags; 1123 err = fdisp_wait_answ(fdip2); 1124 if (err) 1125 goto out; 1126 foo = fdip2->answ; 1127 } 1128 err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vap->va_type); 1129 if (err) { 1130 struct fuse_release_in *fri; 1131 uint64_t nodeid = feo->nodeid; 1132 uint64_t fh_id = foo->fh; 1133 1134 fdisp_destroy(fdip); 1135 fdisp_init(fdip, sizeof(*fri)); 1136 fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred); 1137 fri = fdip->indata; 1138 fri->fh = fh_id; 1139 fri->flags = flags; 1140 fuse_insert_callback(fdip->tick, fuse_internal_forget_callback); 1141 fuse_insert_message(fdip->tick, false); 1142 goto out; 1143 } 1144 ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create"); 1145 fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid, 1146 feo->attr_valid_nsec, NULL, true); 1147 1148 fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, td, cred, foo); 1149 fuse_vnode_open(*vpp, foo->open_flags, td); 1150 /* 1151 * Purge the parent's attribute cache because the daemon should've 1152 * updated its mtime and ctime 1153 */ 1154 fuse_vnode_clear_attr_cache(dvp); 1155 cache_purge_negative(dvp); 1156 1157 out: 1158 if (fdip2) 1159 fdisp_destroy(fdip2); 1160 fdisp_destroy(fdip); 1161 return err; 1162 } 1163 1164 /* 1165 struct vnop_fdatasync_args { 1166 struct vop_generic_args a_gen; 1167 struct vnode * a_vp; 1168 struct thread * a_td; 1169 }; 1170 */ 1171 static int 1172 fuse_vnop_fdatasync(struct vop_fdatasync_args *ap) 1173 { 1174 struct vnode *vp = ap->a_vp; 1175 struct thread *td = ap->a_td; 1176 int waitfor = MNT_WAIT; 1177 1178 int err = 0; 1179 1180 if (fuse_isdeadfs(vp)) { 1181 return 0; 1182 } 1183 if ((err = vop_stdfdatasync_buf(ap))) 1184 return err; 1185 1186 return fuse_internal_fsync(vp, td, waitfor, true); 1187 } 1188 1189 /* 1190 struct vnop_fsync_args { 1191 struct vop_generic_args a_gen; 1192 struct vnode * a_vp; 1193 int a_waitfor; 1194 struct thread * a_td; 1195 }; 1196 */ 1197 static int 1198 fuse_vnop_fsync(struct vop_fsync_args *ap) 1199 { 1200 struct vnode *vp = ap->a_vp; 1201 struct thread *td = ap->a_td; 1202 int waitfor = ap->a_waitfor; 1203 int err = 0; 1204 1205 if (fuse_isdeadfs(vp)) { 1206 return 0; 1207 } 1208 if ((err = vop_stdfsync(ap))) 1209 return err; 1210 1211 return fuse_internal_fsync(vp, td, waitfor, false); 1212 } 1213 1214 /* 1215 struct vnop_getattr_args { 1216 struct vnode *a_vp; 1217 struct vattr *a_vap; 1218 struct ucred *a_cred; 1219 struct thread *a_td; 1220 }; 1221 */ 1222 static int 1223 fuse_vnop_getattr(struct vop_getattr_args *ap) 1224 { 1225 struct vnode *vp = ap->a_vp; 1226 struct vattr *vap = ap->a_vap; 1227 struct ucred *cred = ap->a_cred; 1228 struct thread *td = curthread; 1229 int err = 0; 1230 1231 err = fuse_internal_getattr(vp, vap, cred, td); 1232 if (err == ENOTCONN && vnode_isvroot(vp)) { 1233 /* 1234 * We want to seem a legitimate fs even if the daemon is dead, 1235 * so that, eg., we can still do path based unmounting after 1236 * the daemon dies. 1237 */ 1238 err = 0; 1239 bzero(vap, sizeof(*vap)); 1240 vap->va_type = vnode_vtype(vp); 1241 } 1242 return err; 1243 } 1244 1245 /* 1246 struct vnop_inactive_args { 1247 struct vnode *a_vp; 1248 }; 1249 */ 1250 static int 1251 fuse_vnop_inactive(struct vop_inactive_args *ap) 1252 { 1253 struct vnode *vp = ap->a_vp; 1254 struct thread *td = curthread; 1255 1256 struct fuse_vnode_data *fvdat = VTOFUD(vp); 1257 struct fuse_filehandle *fufh, *fufh_tmp; 1258 1259 int need_flush = 1; 1260 1261 LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) { 1262 if (need_flush && vp->v_type == VREG) { 1263 if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) { 1264 fuse_vnode_savesize(vp, NULL, 0); 1265 } 1266 if ((fvdat->flag & FN_REVOKED) != 0) 1267 fuse_io_invalbuf(vp, td); 1268 else 1269 fuse_io_flushbuf(vp, MNT_WAIT, td); 1270 need_flush = 0; 1271 } 1272 fuse_filehandle_close(vp, fufh, td, NULL); 1273 } 1274 1275 if ((fvdat->flag & FN_REVOKED) != 0) 1276 vrecycle(vp); 1277 1278 return 0; 1279 } 1280 1281 /* 1282 struct vnop_ioctl_args { 1283 struct vnode *a_vp; 1284 u_long a_command; 1285 caddr_t a_data; 1286 int a_fflag; 1287 struct ucred *a_cred; 1288 struct thread *a_td; 1289 }; 1290 */ 1291 static int 1292 fuse_vnop_ioctl(struct vop_ioctl_args *ap) 1293 { 1294 struct vnode *vp = ap->a_vp; 1295 struct mount *mp = vnode_mount(vp); 1296 struct ucred *cred = ap->a_cred; 1297 off_t *offp; 1298 pid_t pid = ap->a_td->td_proc->p_pid; 1299 int err; 1300 1301 switch (ap->a_command) { 1302 case FIOSEEKDATA: 1303 case FIOSEEKHOLE: 1304 /* Call FUSE_LSEEK, if we can, or fall back to vop_stdioctl */ 1305 if (fsess_maybe_impl(mp, FUSE_LSEEK)) { 1306 int whence; 1307 1308 offp = ap->a_data; 1309 if (ap->a_command == FIOSEEKDATA) 1310 whence = SEEK_DATA; 1311 else 1312 whence = SEEK_HOLE; 1313 1314 vn_lock(vp, LK_SHARED | LK_RETRY); 1315 err = fuse_vnop_do_lseek(vp, ap->a_td, cred, pid, offp, 1316 whence); 1317 VOP_UNLOCK(vp); 1318 } 1319 if (fsess_not_impl(mp, FUSE_LSEEK)) 1320 err = vop_stdioctl(ap); 1321 break; 1322 default: 1323 /* TODO: implement FUSE_IOCTL */ 1324 err = ENOTTY; 1325 break; 1326 } 1327 return (err); 1328 } 1329 1330 1331 /* 1332 struct vnop_link_args { 1333 struct vnode *a_tdvp; 1334 struct vnode *a_vp; 1335 struct componentname *a_cnp; 1336 }; 1337 */ 1338 static int 1339 fuse_vnop_link(struct vop_link_args *ap) 1340 { 1341 struct vnode *vp = ap->a_vp; 1342 struct vnode *tdvp = ap->a_tdvp; 1343 struct componentname *cnp = ap->a_cnp; 1344 1345 struct vattr *vap = VTOVA(vp); 1346 1347 struct fuse_dispatcher fdi; 1348 struct fuse_entry_out *feo; 1349 struct fuse_link_in fli; 1350 1351 int err; 1352 1353 if (fuse_isdeadfs(vp)) { 1354 return (EXTERROR(ENXIO, "This FUSE session is about " 1355 "to be closed")); 1356 } 1357 if (vnode_mount(tdvp) != vnode_mount(vp)) { 1358 return (EXDEV); 1359 } 1360 1361 /* 1362 * This is a seatbelt check to protect naive userspace filesystems from 1363 * themselves and the limitations of the FUSE IPC protocol. If a 1364 * filesystem does not allow attribute caching, assume it is capable of 1365 * validating that nlink does not overflow. 1366 */ 1367 if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX) 1368 return (EMLINK); 1369 fli.oldnodeid = VTOI(vp); 1370 1371 fdisp_init(&fdi, 0); 1372 fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp, 1373 FUSE_LINK, &fli, sizeof(fli), &fdi); 1374 if ((err = fdisp_wait_answ(&fdi))) { 1375 goto out; 1376 } 1377 feo = fdi.answ; 1378 1379 if (fli.oldnodeid != feo->nodeid) { 1380 static const char exterr[] = "Server assigned wrong inode " 1381 "for a hard link."; 1382 struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); 1383 fuse_warn(data, FSESS_WARN_ILLEGAL_INODE, exterr); 1384 fuse_vnode_clear_attr_cache(vp); 1385 fuse_vnode_clear_attr_cache(tdvp); 1386 err = EXTERROR(EIO, exterr); 1387 goto out; 1388 } 1389 1390 err = fuse_internal_checkentry(feo, vnode_vtype(vp)); 1391 if (!err) { 1392 /* 1393 * Purge the parent's attribute cache because the daemon 1394 * should've updated its mtime and ctime 1395 */ 1396 fuse_vnode_clear_attr_cache(tdvp); 1397 fuse_internal_cache_attrs(vp, &feo->attr, feo->attr_valid, 1398 feo->attr_valid_nsec, NULL, true); 1399 } 1400 out: 1401 fdisp_destroy(&fdi); 1402 return err; 1403 } 1404 1405 struct fuse_lookup_alloc_arg { 1406 struct fuse_entry_out *feo; 1407 struct componentname *cnp; 1408 uint64_t nid; 1409 __enum_uint8(vtype) vtyp; 1410 }; 1411 1412 /* Callback for vn_get_ino */ 1413 static int 1414 fuse_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp) 1415 { 1416 struct fuse_lookup_alloc_arg *flaa = arg; 1417 1418 return fuse_vnode_get(mp, flaa->feo, flaa->nid, NULL, vpp, flaa->cnp, 1419 flaa->vtyp); 1420 } 1421 1422 SDT_PROBE_DEFINE3(fusefs, , vnops, cache_lookup, 1423 "int", "struct timespec*", "struct timespec*"); 1424 /* 1425 struct vnop_lookup_args { 1426 struct vnodeop_desc *a_desc; 1427 struct vnode *a_dvp; 1428 struct vnode **a_vpp; 1429 struct componentname *a_cnp; 1430 }; 1431 */ 1432 int 1433 fuse_vnop_lookup(struct vop_lookup_args *ap) 1434 { 1435 struct vnode *dvp = ap->a_dvp; 1436 struct vnode **vpp = ap->a_vpp; 1437 struct componentname *cnp = ap->a_cnp; 1438 struct thread *td = curthread; 1439 struct ucred *cred = cnp->cn_cred; 1440 struct timespec now; 1441 1442 int nameiop = cnp->cn_nameiop; 1443 bool isdotdot = cnp->cn_flags & ISDOTDOT; 1444 bool islastcn = cnp->cn_flags & ISLASTCN; 1445 struct mount *mp = vnode_mount(dvp); 1446 struct fuse_data *data = fuse_get_mpdata(mp); 1447 int default_permissions = data->dataflags & FSESS_DEFAULT_PERMISSIONS; 1448 bool is_dot; 1449 1450 int err = 0; 1451 int lookup_err = 0; 1452 struct vnode *vp = NULL; 1453 1454 struct fuse_dispatcher fdi; 1455 bool did_lookup = false; 1456 struct fuse_entry_out *feo = NULL; 1457 __enum_uint8(vtype) vtyp; /* vnode type of target */ 1458 1459 uint64_t nid; 1460 1461 if (fuse_isdeadfs(dvp)) { 1462 *vpp = NULL; 1463 return (EXTERROR(ENXIO, "This FUSE session is about " 1464 "to be closed")); 1465 } 1466 if (!vnode_isdir(dvp)) 1467 return ENOTDIR; 1468 1469 if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP)) 1470 return EROFS; 1471 1472 if ((cnp->cn_flags & NOEXECCHECK) != 0) 1473 cnp->cn_flags &= ~NOEXECCHECK; 1474 else if ((err = fuse_internal_access(dvp, VEXEC, td, cred))) 1475 return err; 1476 1477 is_dot = cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.'; 1478 if (isdotdot && !(data->dataflags & FSESS_EXPORT_SUPPORT)) { 1479 if (!(VTOFUD(dvp)->flag & FN_PARENT_NID)) { 1480 /* 1481 * Since the file system doesn't support ".." lookups, 1482 * we have no way to find this entry. 1483 */ 1484 return (EXTERROR(ESTALE, "This server does not support " 1485 "'..' lookups")); 1486 } 1487 nid = VTOFUD(dvp)->parent_nid; 1488 if (nid == 0) 1489 return ENOENT; 1490 /* .. is obviously a directory */ 1491 vtyp = VDIR; 1492 } else if (is_dot) { 1493 nid = VTOI(dvp); 1494 /* . is obviously a directory */ 1495 vtyp = VDIR; 1496 } else { 1497 struct timespec timeout; 1498 int ncpticks; /* here to accommodate for API contract */ 1499 1500 err = cache_lookup(dvp, vpp, cnp, &timeout, &ncpticks); 1501 getnanouptime(&now); 1502 SDT_PROBE3(fusefs, , vnops, cache_lookup, err, &timeout, &now); 1503 switch (err) { 1504 case -1: /* positive match */ 1505 if (timespeccmp(&timeout, &now, >)) { 1506 counter_u64_add(fuse_lookup_cache_hits, 1); 1507 } else { 1508 /* Cache timeout */ 1509 counter_u64_add(fuse_lookup_cache_misses, 1); 1510 bintime_clear( 1511 &VTOFUD(*vpp)->entry_cache_timeout); 1512 cache_purge(*vpp); 1513 if (dvp != *vpp) 1514 vput(*vpp); 1515 else 1516 vrele(*vpp); 1517 *vpp = NULL; 1518 break; 1519 } 1520 return 0; 1521 1522 case 0: /* no match in cache */ 1523 counter_u64_add(fuse_lookup_cache_misses, 1); 1524 break; 1525 1526 case ENOENT: /* negative match */ 1527 if (timespeccmp(&timeout, &now, <=)) { 1528 /* Cache timeout */ 1529 cache_purge_negative(dvp); 1530 break; 1531 } 1532 /* fall through */ 1533 default: 1534 return err; 1535 } 1536 1537 fdisp_init(&fdi, cnp->cn_namelen + 1); 1538 fdisp_make(&fdi, FUSE_LOOKUP, mp, VTOI(dvp), td, cred); 1539 1540 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 1541 ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 1542 lookup_err = fdisp_wait_answ(&fdi); 1543 did_lookup = true; 1544 1545 if (!lookup_err) { 1546 /* lookup call succeeded */ 1547 feo = (struct fuse_entry_out *)fdi.answ; 1548 nid = feo->nodeid; 1549 if (nid == 0) { 1550 /* zero nodeid means ENOENT and cache it */ 1551 struct timespec timeout; 1552 1553 fdi.answ_stat = ENOENT; 1554 lookup_err = ENOENT; 1555 if (cnp->cn_flags & MAKEENTRY) { 1556 fuse_validity_2_timespec(feo, &timeout); 1557 /* Use the same entry_time for .. as for 1558 * the file itself. That doesn't honor 1559 * exactly what the fuse server tells 1560 * us, but to do otherwise would require 1561 * another cache lookup at this point. 1562 */ 1563 struct timespec *dtsp = NULL; 1564 cache_enter_time(dvp, *vpp, cnp, 1565 &timeout, dtsp); 1566 } 1567 } 1568 vtyp = IFTOVT(feo->attr.mode); 1569 } 1570 if (lookup_err && (!fdi.answ_stat || lookup_err != ENOENT)) { 1571 fdisp_destroy(&fdi); 1572 return lookup_err; 1573 } 1574 } 1575 /* lookup_err, if non-zero, must be ENOENT at this point */ 1576 1577 if (lookup_err) { 1578 /* Entry not found */ 1579 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { 1580 if (default_permissions) 1581 err = fuse_internal_access(dvp, VWRITE, td, 1582 cred); 1583 else 1584 err = 0; 1585 if (!err) { 1586 err = EJUSTRETURN; 1587 } 1588 } else { 1589 err = ENOENT; 1590 } 1591 } else { 1592 /* Entry was found */ 1593 if (isdotdot) { 1594 struct fuse_lookup_alloc_arg flaa; 1595 1596 flaa.nid = nid; 1597 flaa.feo = feo; 1598 flaa.cnp = cnp; 1599 flaa.vtyp = vtyp; 1600 err = vn_vget_ino_gen(dvp, fuse_lookup_alloc, &flaa, 0, 1601 &vp); 1602 *vpp = vp; 1603 } else if (nid == VTOI(dvp)) { 1604 if (is_dot) { 1605 vref(dvp); 1606 *vpp = dvp; 1607 } else { 1608 static const char exterr[] = "Server assigned " 1609 "same inode to both parent and child."; 1610 fuse_warn(fuse_get_mpdata(mp), 1611 FSESS_WARN_ILLEGAL_INODE, exterr); 1612 err = EXTERROR(EIO, exterr); 1613 } 1614 1615 } else { 1616 struct fuse_vnode_data *fvdat; 1617 1618 err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp, 1619 &vp, cnp, vtyp); 1620 if (err) 1621 goto out; 1622 *vpp = vp; 1623 fvdat = VTOFUD(vp); 1624 1625 MPASS(feo != NULL); 1626 if (timespeccmp(&now, &fvdat->last_local_modify, >)) { 1627 /* 1628 * Attributes from the server are definitely 1629 * newer than the last attributes we sent to 1630 * the server, so cache them. 1631 */ 1632 fuse_internal_cache_attrs(*vpp, &feo->attr, 1633 feo->attr_valid, feo->attr_valid_nsec, 1634 NULL, true); 1635 } 1636 fuse_validity_2_bintime(feo->entry_valid, 1637 feo->entry_valid_nsec, 1638 &fvdat->entry_cache_timeout); 1639 1640 if ((nameiop == DELETE || nameiop == RENAME) && 1641 islastcn && default_permissions) 1642 { 1643 struct vattr dvattr; 1644 1645 err = fuse_internal_access(dvp, VWRITE, td, 1646 cred); 1647 if (err != 0) 1648 goto out; 1649 /* 1650 * if the parent's sticky bit is set, check 1651 * whether we're allowed to remove the file. 1652 * Need to figure out the vnode locking to make 1653 * this work. 1654 */ 1655 fuse_internal_getattr(dvp, &dvattr, cred, td); 1656 if ((dvattr.va_mode & S_ISTXT) && 1657 fuse_internal_access(dvp, VADMIN, td, 1658 cred) && 1659 fuse_internal_access(*vpp, VADMIN, td, 1660 cred)) { 1661 err = EPERM; 1662 goto out; 1663 } 1664 } 1665 } 1666 } 1667 out: 1668 if (err) { 1669 if (vp != NULL && dvp != vp) 1670 vput(vp); 1671 else if (vp != NULL) 1672 vrele(vp); 1673 *vpp = NULL; 1674 } 1675 if (did_lookup) 1676 fdisp_destroy(&fdi); 1677 1678 return err; 1679 } 1680 1681 /* 1682 struct vnop_mkdir_args { 1683 struct vnode *a_dvp; 1684 struct vnode **a_vpp; 1685 struct componentname *a_cnp; 1686 struct vattr *a_vap; 1687 }; 1688 */ 1689 static int 1690 fuse_vnop_mkdir(struct vop_mkdir_args *ap) 1691 { 1692 struct vnode *dvp = ap->a_dvp; 1693 struct vnode **vpp = ap->a_vpp; 1694 struct componentname *cnp = ap->a_cnp; 1695 struct vattr *vap = ap->a_vap; 1696 1697 struct fuse_mkdir_in fmdi; 1698 1699 if (fuse_isdeadfs(dvp)) { 1700 return (EXTERROR(ENXIO, "This FUSE session is about " 1701 "to be closed")); 1702 } 1703 fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode); 1704 fmdi.umask = curthread->td_proc->p_pd->pd_cmask; 1705 1706 return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi, 1707 sizeof(fmdi), VDIR)); 1708 } 1709 1710 /* 1711 struct vnop_mknod_args { 1712 struct vnode *a_dvp; 1713 struct vnode **a_vpp; 1714 struct componentname *a_cnp; 1715 struct vattr *a_vap; 1716 }; 1717 */ 1718 static int 1719 fuse_vnop_mknod(struct vop_mknod_args *ap) 1720 { 1721 1722 struct vnode *dvp = ap->a_dvp; 1723 struct vnode **vpp = ap->a_vpp; 1724 struct componentname *cnp = ap->a_cnp; 1725 struct vattr *vap = ap->a_vap; 1726 1727 if (fuse_isdeadfs(dvp)) 1728 return (EXTERROR(ENXIO, "This FUSE session is about " 1729 "to be closed")); 1730 1731 return fuse_internal_mknod(dvp, vpp, cnp, vap); 1732 } 1733 1734 /* 1735 struct vop_open_args { 1736 struct vnode *a_vp; 1737 int a_mode; 1738 struct ucred *a_cred; 1739 struct thread *a_td; 1740 int a_fdidx; / struct file *a_fp; 1741 }; 1742 */ 1743 static int 1744 fuse_vnop_open(struct vop_open_args *ap) 1745 { 1746 struct vnode *vp = ap->a_vp; 1747 int a_mode = ap->a_mode; 1748 struct thread *td = ap->a_td; 1749 struct ucred *cred = ap->a_cred; 1750 pid_t pid = td->td_proc->p_pid; 1751 1752 if (fuse_isdeadfs(vp)) 1753 return (EXTERROR(ENXIO, "This FUSE session is about " 1754 "to be closed")); 1755 if (VN_ISDEV(vp) || vp->v_type == VFIFO) 1756 return (EXTERROR(EOPNOTSUPP, "Unsupported vnode type", 1757 vp->v_type)); 1758 if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0) 1759 return (EXTERROR(EINVAL, "Illegal mode", a_mode)); 1760 1761 if (fuse_filehandle_validrw(vp, a_mode, cred, pid)) { 1762 fuse_vnode_open(vp, 0, td); 1763 return 0; 1764 } 1765 1766 return fuse_filehandle_open(vp, a_mode, NULL, td, cred); 1767 } 1768 1769 static int 1770 fuse_vnop_pathconf(struct vop_pathconf_args *ap) 1771 { 1772 struct vnode *vp = ap->a_vp; 1773 struct mount *mp; 1774 struct fuse_filehandle *fufh; 1775 int err; 1776 bool closefufh = false; 1777 1778 switch (ap->a_name) { 1779 case _PC_FILESIZEBITS: 1780 *ap->a_retval = 64; 1781 return (0); 1782 case _PC_NAME_MAX: 1783 *ap->a_retval = NAME_MAX; 1784 return (0); 1785 case _PC_LINK_MAX: 1786 *ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX); 1787 return (0); 1788 case _PC_SYMLINK_MAX: 1789 *ap->a_retval = MAXPATHLEN; 1790 return (0); 1791 case _PC_NO_TRUNC: 1792 *ap->a_retval = 1; 1793 return (0); 1794 case _PC_MIN_HOLE_SIZE: 1795 /* 1796 * The FUSE protocol provides no mechanism for a server to 1797 * report _PC_MIN_HOLE_SIZE. It's a protocol bug. Instead, 1798 * return EINVAL if the server does not support FUSE_LSEEK, or 1799 * 1 if it does. 1800 */ 1801 mp = vnode_mount(vp); 1802 if (!fsess_is_impl(mp, FUSE_LSEEK) && 1803 !fsess_not_impl(mp, FUSE_LSEEK)) { 1804 off_t offset = 0; 1805 1806 /* 1807 * Issue a FUSE_LSEEK to find out if it's supported. 1808 * Use SEEK_DATA instead of SEEK_HOLE, because the 1809 * latter generally requires sequential scans of file 1810 * metadata, which can be slow. 1811 */ 1812 err = fuse_vnop_do_lseek(vp, curthread, 1813 curthread->td_ucred, curthread->td_proc->p_pid, 1814 &offset, SEEK_DATA); 1815 if (err == EBADF) { 1816 /* 1817 * pathconf() doesn't necessarily open the 1818 * file. So we may need to do it here. 1819 */ 1820 err = fuse_filehandle_open(vp, FREAD, &fufh, 1821 curthread, curthread->td_ucred); 1822 if (err == 0) { 1823 closefufh = true; 1824 err = fuse_vnop_do_lseek(vp, curthread, 1825 curthread->td_ucred, 1826 curthread->td_proc->p_pid, &offset, 1827 SEEK_DATA); 1828 } 1829 if (closefufh) 1830 fuse_filehandle_close(vp, fufh, 1831 curthread, curthread->td_ucred); 1832 } 1833 1834 } 1835 1836 if (fsess_is_impl(mp, FUSE_LSEEK)) { 1837 *ap->a_retval = 1; 1838 return (0); 1839 } else if (fsess_not_impl(mp, FUSE_LSEEK)) { 1840 /* FUSE_LSEEK is not implemented */ 1841 return (EXTERROR(EINVAL, "This server does not " 1842 "implement FUSE_LSEEK")); 1843 } else { 1844 return (err); 1845 } 1846 default: 1847 return (vop_stdpathconf(ap)); 1848 } 1849 } 1850 1851 SDT_PROBE_DEFINE3(fusefs, , vnops, filehandles_closed, "struct vnode*", 1852 "struct uio*", "struct ucred*"); 1853 /* 1854 struct vnop_read_args { 1855 struct vnode *a_vp; 1856 struct uio *a_uio; 1857 int a_ioflag; 1858 struct ucred *a_cred; 1859 }; 1860 */ 1861 static int 1862 fuse_vnop_read(struct vop_read_args *ap) 1863 { 1864 struct vnode *vp = ap->a_vp; 1865 struct uio *uio = ap->a_uio; 1866 int ioflag = ap->a_ioflag; 1867 struct ucred *cred = ap->a_cred; 1868 pid_t pid = curthread->td_proc->p_pid; 1869 struct fuse_filehandle *fufh; 1870 int err; 1871 bool closefufh = false, directio; 1872 1873 MPASS(vp->v_type == VREG || vp->v_type == VDIR); 1874 1875 if (fuse_isdeadfs(vp)) { 1876 return (EXTERROR(ENXIO, "This FUSE session is about " 1877 "to be closed")); 1878 } 1879 1880 if (VTOFUD(vp)->flag & FN_DIRECTIO) { 1881 ioflag |= IO_DIRECT; 1882 } 1883 1884 err = fuse_filehandle_getrw(vp, FREAD, &fufh, cred, pid); 1885 if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) { 1886 /* 1887 * nfsd will do I/O without first doing VOP_OPEN. We 1888 * must implicitly open the file here 1889 */ 1890 err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred); 1891 closefufh = true; 1892 } 1893 if (err) { 1894 SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred); 1895 return err; 1896 } 1897 1898 /* 1899 * Ideally, when the daemon asks for direct io at open time, the 1900 * standard file flag should be set according to this, so that would 1901 * just change the default mode, which later on could be changed via 1902 * fcntl(2). 1903 * But this doesn't work, the O_DIRECT flag gets cleared at some point 1904 * (don't know where). So to make any use of the Fuse direct_io option, 1905 * we hardwire it into the file's private data (similarly to Linux, 1906 * btw.). 1907 */ 1908 directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp)); 1909 1910 fuse_vnode_update(vp, FN_ATIMECHANGE); 1911 if (directio) { 1912 SDT_PROBE2(fusefs, , vnops, trace, 1, "direct read of vnode"); 1913 err = fuse_read_directbackend(vp, uio, cred, fufh); 1914 } else { 1915 SDT_PROBE2(fusefs, , vnops, trace, 1, "buffered read of vnode"); 1916 err = fuse_read_biobackend(vp, uio, ioflag, cred, fufh, pid); 1917 } 1918 1919 if (closefufh) 1920 fuse_filehandle_close(vp, fufh, curthread, cred); 1921 1922 return (err); 1923 } 1924 1925 /* 1926 struct vnop_readdir_args { 1927 struct vnode *a_vp; 1928 struct uio *a_uio; 1929 struct ucred *a_cred; 1930 int *a_eofflag; 1931 int *a_ncookies; 1932 uint64_t **a_cookies; 1933 }; 1934 */ 1935 static int 1936 fuse_vnop_readdir(struct vop_readdir_args *ap) 1937 { 1938 struct vnode *vp = ap->a_vp; 1939 struct uio *uio = ap->a_uio; 1940 struct ucred *cred = ap->a_cred; 1941 struct fuse_filehandle *fufh = NULL; 1942 struct mount *mp = vnode_mount(vp); 1943 struct fuse_iov cookediov; 1944 int err = 0; 1945 uint64_t *cookies; 1946 ssize_t tresid; 1947 int ncookies; 1948 bool closefufh = false; 1949 pid_t pid = curthread->td_proc->p_pid; 1950 1951 if (ap->a_eofflag) 1952 *ap->a_eofflag = 0; 1953 if (fuse_isdeadfs(vp)) { 1954 return (EXTERROR(ENXIO, "This FUSE session is about " 1955 "to be closed")); 1956 } 1957 if (uio_resid(uio) < sizeof(struct dirent)) 1958 return (EXTERROR(EINVAL, "Buffer is too small")); 1959 1960 tresid = uio->uio_resid; 1961 err = fuse_filehandle_get_dir(vp, &fufh, cred, pid); 1962 if (err == EBADF && mp->mnt_flag & MNT_EXPORTED) { 1963 KASSERT(!fsess_is_impl(mp, FUSE_OPENDIR), 1964 ("FUSE file systems that implement " 1965 "FUSE_OPENDIR should not be exported")); 1966 /* 1967 * nfsd will do VOP_READDIR without first doing VOP_OPEN. We 1968 * must implicitly open the directory here. 1969 */ 1970 err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred); 1971 closefufh = true; 1972 } 1973 if (err) 1974 return (err); 1975 if (ap->a_ncookies != NULL) { 1976 ncookies = uio->uio_resid / 1977 (offsetof(struct dirent, d_name) + 4) + 1; 1978 cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK); 1979 *ap->a_ncookies = ncookies; 1980 *ap->a_cookies = cookies; 1981 } else { 1982 ncookies = 0; 1983 cookies = NULL; 1984 } 1985 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1) 1986 fiov_init(&cookediov, DIRCOOKEDSIZE); 1987 1988 err = fuse_internal_readdir(vp, uio, fufh, &cookediov, 1989 &ncookies, cookies); 1990 1991 fiov_teardown(&cookediov); 1992 if (closefufh) 1993 fuse_filehandle_close(vp, fufh, curthread, cred); 1994 1995 if (ap->a_ncookies != NULL) { 1996 if (err == 0) { 1997 *ap->a_ncookies -= ncookies; 1998 } else { 1999 free(*ap->a_cookies, M_TEMP); 2000 *ap->a_ncookies = 0; 2001 *ap->a_cookies = NULL; 2002 } 2003 } 2004 if (err == 0 && tresid == uio->uio_resid) 2005 *ap->a_eofflag = 1; 2006 2007 return err; 2008 } 2009 2010 /* 2011 struct vnop_readlink_args { 2012 struct vnode *a_vp; 2013 struct uio *a_uio; 2014 struct ucred *a_cred; 2015 }; 2016 */ 2017 static int 2018 fuse_vnop_readlink(struct vop_readlink_args *ap) 2019 { 2020 struct vnode *vp = ap->a_vp; 2021 struct uio *uio = ap->a_uio; 2022 struct ucred *cred = ap->a_cred; 2023 2024 struct fuse_dispatcher fdi; 2025 int err; 2026 2027 if (fuse_isdeadfs(vp)) { 2028 return (EXTERROR(ENXIO, "This FUSE session is about " 2029 "to be closed")); 2030 } 2031 if (!vnode_islnk(vp)) { 2032 return EINVAL; 2033 } 2034 fdisp_init(&fdi, 0); 2035 err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred); 2036 if (err) { 2037 goto out; 2038 } 2039 if (strnlen(fdi.answ, fdi.iosize) + 1 < fdi.iosize) { 2040 static const char exterr[] = "Server returned an embedded NUL " 2041 "from FUSE_READLINK."; 2042 struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); 2043 fuse_warn(data, FSESS_WARN_READLINK_EMBEDDED_NUL, exterr); 2044 err = EXTERROR(EIO, exterr); 2045 goto out; 2046 } 2047 if (((char *)fdi.answ)[0] == '/' && 2048 fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) { 2049 char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname; 2050 2051 err = uiomove(mpth, strlen(mpth), uio); 2052 } 2053 if (!err) { 2054 err = uiomove(fdi.answ, fdi.iosize, uio); 2055 } 2056 out: 2057 fdisp_destroy(&fdi); 2058 return err; 2059 } 2060 2061 /* 2062 struct vnop_reclaim_args { 2063 struct vnode *a_vp; 2064 }; 2065 */ 2066 static int 2067 fuse_vnop_reclaim(struct vop_reclaim_args *ap) 2068 { 2069 struct vnode *vp = ap->a_vp; 2070 struct thread *td = curthread; 2071 struct fuse_vnode_data *fvdat = VTOFUD(vp); 2072 struct fuse_filehandle *fufh, *fufh_tmp; 2073 2074 if (!fvdat) { 2075 panic("FUSE: no vnode data during recycling"); 2076 } 2077 LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) { 2078 printf("FUSE: vnode being reclaimed with open fufh " 2079 "(type=%#x)", fufh->fufh_type); 2080 fuse_filehandle_close(vp, fufh, td, NULL); 2081 } 2082 2083 if (VTOI(vp) == 1) { 2084 /* 2085 * Don't send FUSE_FORGET for the root inode, because 2086 * we never send FUSE_LOOKUP for it (see 2087 * fuse_vfsop_root) and we don't want the server to see 2088 * mismatched lookup counts. 2089 */ 2090 struct fuse_data *data; 2091 struct vnode *vroot; 2092 2093 data = fuse_get_mpdata(vnode_mount(vp)); 2094 FUSE_LOCK(); 2095 vroot = data->vroot; 2096 data->vroot = NULL; 2097 FUSE_UNLOCK(); 2098 if (vroot) 2099 vrele(vroot); 2100 } else if (!fuse_isdeadfs(vp) && fvdat->nlookup > 0) { 2101 fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp), 2102 fvdat->nlookup); 2103 } 2104 cache_purge(vp); 2105 vfs_hash_remove(vp); 2106 fuse_vnode_destroy(vp); 2107 2108 return 0; 2109 } 2110 2111 /* 2112 struct vnop_remove_args { 2113 struct vnode *a_dvp; 2114 struct vnode *a_vp; 2115 struct componentname *a_cnp; 2116 }; 2117 */ 2118 static int 2119 fuse_vnop_remove(struct vop_remove_args *ap) 2120 { 2121 struct vnode *dvp = ap->a_dvp; 2122 struct vnode *vp = ap->a_vp; 2123 struct componentname *cnp = ap->a_cnp; 2124 2125 int err; 2126 2127 if (fuse_isdeadfs(vp)) { 2128 return (EXTERROR(ENXIO, "This FUSE session is about " 2129 "to be closed")); 2130 } 2131 if (vnode_isdir(vp)) { 2132 return (EXTERROR(EPERM, "vnode is a directory")); 2133 } 2134 2135 err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK); 2136 2137 return err; 2138 } 2139 2140 /* 2141 struct vnop_rename_args { 2142 struct vnode *a_fdvp; 2143 struct vnode *a_fvp; 2144 struct componentname *a_fcnp; 2145 struct vnode *a_tdvp; 2146 struct vnode *a_tvp; 2147 struct componentname *a_tcnp; 2148 }; 2149 */ 2150 static int 2151 fuse_vnop_rename(struct vop_rename_args *ap) 2152 { 2153 struct vnode *fdvp = ap->a_fdvp; 2154 struct vnode *fvp = ap->a_fvp; 2155 struct componentname *fcnp = ap->a_fcnp; 2156 struct vnode *tdvp = ap->a_tdvp; 2157 struct vnode *tvp = ap->a_tvp; 2158 struct componentname *tcnp = ap->a_tcnp; 2159 struct fuse_data *data; 2160 bool newparent = fdvp != tdvp; 2161 bool isdir = fvp->v_type == VDIR; 2162 int err = 0; 2163 2164 if (fuse_isdeadfs(fdvp)) { 2165 return (EXTERROR(ENXIO, "This FUSE session is about " 2166 "to be closed")); 2167 } 2168 if (fvp->v_mount != tdvp->v_mount || 2169 (tvp && fvp->v_mount != tvp->v_mount)) { 2170 SDT_PROBE2(fusefs, , vnops, trace, 1, "cross-device rename"); 2171 err = EXTERROR(EXDEV, "Cross-device rename"); 2172 goto out; 2173 } 2174 cache_purge(fvp); 2175 2176 /* 2177 * FUSE library is expected to check if target directory is not 2178 * under the source directory in the file system tree. 2179 * Linux performs this check at VFS level. 2180 */ 2181 /* 2182 * If source is a directory, and it will get a new parent, user must 2183 * have write permission to it, so ".." can be modified. 2184 */ 2185 data = fuse_get_mpdata(vnode_mount(tdvp)); 2186 if (data->dataflags & FSESS_DEFAULT_PERMISSIONS && isdir && newparent) { 2187 err = fuse_internal_access(fvp, VWRITE, 2188 curthread, tcnp->cn_cred); 2189 if (err) 2190 goto out; 2191 } 2192 sx_xlock(&data->rename_lock); 2193 err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp); 2194 if (err == 0) { 2195 if (tdvp != fdvp) 2196 fuse_vnode_setparent(fvp, tdvp); 2197 if (tvp != NULL) 2198 fuse_vnode_setparent(tvp, NULL); 2199 } 2200 sx_unlock(&data->rename_lock); 2201 2202 if (tvp != NULL && tvp != fvp) { 2203 cache_purge(tvp); 2204 } 2205 if (vnode_isdir(fvp)) { 2206 if (((tvp != NULL) && vnode_isdir(tvp)) || vnode_isdir(fvp)) { 2207 cache_purge(tdvp); 2208 } 2209 cache_purge(fdvp); 2210 } 2211 out: 2212 if (tdvp == tvp) { 2213 vrele(tdvp); 2214 } else { 2215 vput(tdvp); 2216 } 2217 if (tvp != NULL) { 2218 vput(tvp); 2219 } 2220 vrele(fdvp); 2221 vrele(fvp); 2222 2223 return err; 2224 } 2225 2226 /* 2227 struct vnop_rmdir_args { 2228 struct vnode *a_dvp; 2229 struct vnode *a_vp; 2230 struct componentname *a_cnp; 2231 } *ap; 2232 */ 2233 static int 2234 fuse_vnop_rmdir(struct vop_rmdir_args *ap) 2235 { 2236 struct vnode *dvp = ap->a_dvp; 2237 struct vnode *vp = ap->a_vp; 2238 2239 int err; 2240 2241 if (fuse_isdeadfs(vp)) { 2242 return (EXTERROR(ENXIO, "This FUSE session is about " 2243 "to be closed")); 2244 } 2245 if (VTOFUD(vp) == VTOFUD(dvp)) { 2246 return (EXTERROR(EINVAL, "Directory to be removed " 2247 "contains itself")); 2248 } 2249 err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR); 2250 2251 return err; 2252 } 2253 2254 /* 2255 struct vnop_setattr_args { 2256 struct vnode *a_vp; 2257 struct vattr *a_vap; 2258 struct ucred *a_cred; 2259 struct thread *a_td; 2260 }; 2261 */ 2262 static int 2263 fuse_vnop_setattr(struct vop_setattr_args *ap) 2264 { 2265 struct vnode *vp = ap->a_vp; 2266 struct vattr *vap = ap->a_vap; 2267 struct ucred *cred = ap->a_cred; 2268 struct thread *td = curthread; 2269 struct mount *mp; 2270 struct fuse_data *data; 2271 struct vattr old_va; 2272 int dataflags; 2273 int err = 0, err2; 2274 accmode_t accmode = 0; 2275 bool checkperm; 2276 bool drop_suid = false; 2277 2278 mp = vnode_mount(vp); 2279 data = fuse_get_mpdata(mp); 2280 dataflags = data->dataflags; 2281 checkperm = dataflags & FSESS_DEFAULT_PERMISSIONS; 2282 2283 if (fuse_isdeadfs(vp)) { 2284 return (EXTERROR(ENXIO, "This FUSE session is about " 2285 "to be closed")); 2286 } 2287 2288 if (vap->va_uid != (uid_t)VNOVAL) { 2289 if (checkperm) { 2290 /* Only root may change a file's owner */ 2291 err = priv_check_cred(cred, PRIV_VFS_CHOWN); 2292 if (err) { 2293 /* As a special case, allow the null chown */ 2294 err2 = fuse_internal_getattr(vp, &old_va, cred, 2295 td); 2296 if (err2) 2297 return (err2); 2298 if (vap->va_uid != old_va.va_uid) 2299 return err; 2300 drop_suid = true; 2301 } 2302 } 2303 accmode |= VADMIN; 2304 } 2305 if (vap->va_gid != (gid_t)VNOVAL) { 2306 if (checkperm && priv_check_cred(cred, PRIV_VFS_CHOWN)) 2307 drop_suid = true; 2308 if (checkperm && !groupmember(vap->va_gid, cred)) { 2309 /* 2310 * Non-root users may only chgrp to one of their own 2311 * groups 2312 */ 2313 err = priv_check_cred(cred, PRIV_VFS_CHOWN); 2314 if (err) { 2315 /* As a special case, allow the null chgrp */ 2316 err2 = fuse_internal_getattr(vp, &old_va, cred, 2317 td); 2318 if (err2) 2319 return (err2); 2320 if (vap->va_gid != old_va.va_gid) 2321 return err; 2322 } 2323 } 2324 accmode |= VADMIN; 2325 } 2326 if (vap->va_size != VNOVAL) { 2327 switch (vp->v_type) { 2328 case VDIR: 2329 return (EISDIR); 2330 case VLNK: 2331 case VREG: 2332 if (vfs_isrdonly(mp)) 2333 return (EROFS); 2334 err = vn_rlimit_trunc(vap->va_size, td); 2335 if (err) 2336 return (err); 2337 break; 2338 default: 2339 /* 2340 * According to POSIX, the result is unspecified 2341 * for file types other than regular files, 2342 * directories and shared memory objects. We 2343 * don't support shared memory objects in the file 2344 * system, and have dubious support for truncating 2345 * symlinks. Just ignore the request in other cases. 2346 */ 2347 return (0); 2348 } 2349 /* Don't set accmode. Permission to trunc is checked upstack */ 2350 } 2351 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 2352 if (vap->va_vaflags & VA_UTIMES_NULL) 2353 accmode |= VWRITE; 2354 else 2355 accmode |= VADMIN; 2356 } 2357 if (drop_suid) { 2358 if (vap->va_mode != (mode_t)VNOVAL) 2359 vap->va_mode &= ~(S_ISUID | S_ISGID); 2360 else { 2361 err = fuse_internal_getattr(vp, &old_va, cred, td); 2362 if (err) 2363 return (err); 2364 vap->va_mode = old_va.va_mode & ~(S_ISUID | S_ISGID); 2365 } 2366 } 2367 if (vap->va_mode != (mode_t)VNOVAL) { 2368 /* Only root may set the sticky bit on non-directories */ 2369 if (checkperm && vp->v_type != VDIR && (vap->va_mode & S_ISTXT) 2370 && priv_check_cred(cred, PRIV_VFS_STICKYFILE)) 2371 return EFTYPE; 2372 if (checkperm && (vap->va_mode & S_ISGID)) { 2373 err = fuse_internal_getattr(vp, &old_va, cred, td); 2374 if (err) 2375 return (err); 2376 if (!groupmember(old_va.va_gid, cred)) { 2377 err = priv_check_cred(cred, PRIV_VFS_SETGID); 2378 if (err) 2379 return (err); 2380 } 2381 } 2382 accmode |= VADMIN; 2383 } 2384 2385 if (vfs_isrdonly(mp)) 2386 return EROFS; 2387 2388 if (checkperm) { 2389 err = fuse_internal_access(vp, accmode, td, cred); 2390 } else { 2391 err = 0; 2392 } 2393 if (err) 2394 return err; 2395 else 2396 return fuse_internal_setattr(vp, vap, td, cred); 2397 } 2398 2399 /* 2400 struct vnop_strategy_args { 2401 struct vnode *a_vp; 2402 struct buf *a_bp; 2403 }; 2404 */ 2405 static int 2406 fuse_vnop_strategy(struct vop_strategy_args *ap) 2407 { 2408 struct vnode *vp = ap->a_vp; 2409 struct buf *bp = ap->a_bp; 2410 2411 if (!vp || fuse_isdeadfs(vp)) { 2412 bp->b_ioflags |= BIO_ERROR; 2413 bp->b_error = ENXIO; 2414 bufdone(bp); 2415 return 0; 2416 } 2417 2418 /* 2419 * VOP_STRATEGY always returns zero and signals error via bp->b_ioflags. 2420 * fuse_io_strategy sets bp's error fields 2421 */ 2422 (void)fuse_io_strategy(vp, bp); 2423 2424 return 0; 2425 } 2426 2427 /* 2428 struct vnop_symlink_args { 2429 struct vnode *a_dvp; 2430 struct vnode **a_vpp; 2431 struct componentname *a_cnp; 2432 struct vattr *a_vap; 2433 char *a_target; 2434 }; 2435 */ 2436 static int 2437 fuse_vnop_symlink(struct vop_symlink_args *ap) 2438 { 2439 struct vnode *dvp = ap->a_dvp; 2440 struct vnode **vpp = ap->a_vpp; 2441 struct componentname *cnp = ap->a_cnp; 2442 const char *target = ap->a_target; 2443 2444 struct fuse_dispatcher fdi; 2445 2446 int err; 2447 size_t len; 2448 2449 if (fuse_isdeadfs(dvp)) { 2450 return (EXTERROR(ENXIO, "This FUSE session is about " 2451 "to be closed")); 2452 } 2453 /* 2454 * Unlike the other creator type calls, here we have to create a message 2455 * where the name of the new entry comes first, and the data describing 2456 * the entry comes second. 2457 * Hence we can't rely on our handy fuse_internal_newentry() routine, 2458 * but put together the message manually and just call the core part. 2459 */ 2460 2461 len = strlen(target) + 1; 2462 fdisp_init(&fdi, len + cnp->cn_namelen + 1); 2463 fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL); 2464 2465 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 2466 ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 2467 memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len); 2468 2469 err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi); 2470 fdisp_destroy(&fdi); 2471 return err; 2472 } 2473 2474 /* 2475 struct vnop_write_args { 2476 struct vnode *a_vp; 2477 struct uio *a_uio; 2478 int a_ioflag; 2479 struct ucred *a_cred; 2480 }; 2481 */ 2482 static int 2483 fuse_vnop_write(struct vop_write_args *ap) 2484 { 2485 struct vnode *vp = ap->a_vp; 2486 struct uio *uio = ap->a_uio; 2487 int ioflag = ap->a_ioflag; 2488 struct ucred *cred = ap->a_cred; 2489 pid_t pid = curthread->td_proc->p_pid; 2490 struct fuse_filehandle *fufh; 2491 int err; 2492 bool closefufh = false, directio; 2493 2494 MPASS(vp->v_type == VREG || vp->v_type == VDIR); 2495 2496 if (fuse_isdeadfs(vp)) { 2497 return (EXTERROR(ENXIO, "This FUSE session is about " 2498 "to be closed")); 2499 } 2500 2501 if (VTOFUD(vp)->flag & FN_DIRECTIO) { 2502 ioflag |= IO_DIRECT; 2503 } 2504 2505 err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid); 2506 if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) { 2507 /* 2508 * nfsd will do I/O without first doing VOP_OPEN. We 2509 * must implicitly open the file here 2510 */ 2511 err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred); 2512 closefufh = true; 2513 } 2514 if (err) { 2515 SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred); 2516 return err; 2517 } 2518 2519 /* 2520 * Ideally, when the daemon asks for direct io at open time, the 2521 * standard file flag should be set according to this, so that would 2522 * just change the default mode, which later on could be changed via 2523 * fcntl(2). 2524 * But this doesn't work, the O_DIRECT flag gets cleared at some point 2525 * (don't know where). So to make any use of the Fuse direct_io option, 2526 * we hardwire it into the file's private data (similarly to Linux, 2527 * btw.). 2528 */ 2529 directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp)); 2530 2531 fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE); 2532 if (directio) { 2533 off_t start, end, filesize; 2534 bool pages = (ioflag & IO_VMIO) != 0; 2535 2536 SDT_PROBE2(fusefs, , vnops, trace, 1, "direct write of vnode"); 2537 2538 err = fuse_vnode_size(vp, &filesize, cred, curthread); 2539 if (err) 2540 goto out; 2541 2542 start = uio->uio_offset; 2543 end = start + uio->uio_resid; 2544 if (!pages) { 2545 err = fuse_inval_buf_range(vp, filesize, start, 2546 end); 2547 if (err) 2548 goto out; 2549 } 2550 err = fuse_write_directbackend(vp, uio, cred, fufh, 2551 filesize, ioflag, pages); 2552 } else { 2553 SDT_PROBE2(fusefs, , vnops, trace, 1, 2554 "buffered write of vnode"); 2555 if (!fsess_opt_writeback(vnode_mount(vp))) 2556 ioflag |= IO_SYNC; 2557 err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag, pid); 2558 } 2559 fuse_internal_clear_suid_on_write(vp, cred, uio->uio_td); 2560 2561 out: 2562 if (closefufh) 2563 fuse_filehandle_close(vp, fufh, curthread, cred); 2564 2565 return (err); 2566 } 2567 2568 static daddr_t 2569 fuse_gbp_getblkno(struct vnode *vp, vm_ooffset_t off) 2570 { 2571 const int biosize = fuse_iosize(vp); 2572 2573 return (off / biosize); 2574 } 2575 2576 static int 2577 fuse_gbp_getblksz(struct vnode *vp, daddr_t lbn, long *blksz) 2578 { 2579 off_t filesize; 2580 int err; 2581 const int biosize = fuse_iosize(vp); 2582 2583 err = fuse_vnode_size(vp, &filesize, NULL, NULL); 2584 if (err) { 2585 /* This will turn into a SIGBUS */ 2586 return (EIO); 2587 } else if ((off_t)lbn * biosize >= filesize) { 2588 *blksz = 0; 2589 } else if ((off_t)(lbn + 1) * biosize > filesize) { 2590 *blksz = filesize - (off_t)lbn *biosize; 2591 } else { 2592 *blksz = biosize; 2593 } 2594 return (0); 2595 } 2596 2597 /* 2598 struct vnop_getpages_args { 2599 struct vnode *a_vp; 2600 vm_page_t *a_m; 2601 int a_count; 2602 int a_reqpage; 2603 }; 2604 */ 2605 static int 2606 fuse_vnop_getpages(struct vop_getpages_args *ap) 2607 { 2608 struct vnode *vp = ap->a_vp; 2609 2610 if (!fsess_opt_mmap(vnode_mount(vp))) { 2611 SDT_PROBE2(fusefs, , vnops, trace, 1, 2612 "called on non-cacheable vnode??\n"); 2613 return (VM_PAGER_ERROR); 2614 } 2615 2616 return (vfs_bio_getpages(vp, ap->a_m, ap->a_count, ap->a_rbehind, 2617 ap->a_rahead, fuse_gbp_getblkno, fuse_gbp_getblksz)); 2618 } 2619 2620 static const char extattr_namespace_separator = '.'; 2621 2622 /* 2623 struct vop_getextattr_args { 2624 struct vop_generic_args a_gen; 2625 struct vnode *a_vp; 2626 int a_attrnamespace; 2627 const char *a_name; 2628 struct uio *a_uio; 2629 size_t *a_size; 2630 struct ucred *a_cred; 2631 struct thread *a_td; 2632 }; 2633 */ 2634 static int 2635 fuse_vnop_getextattr(struct vop_getextattr_args *ap) 2636 { 2637 struct vnode *vp = ap->a_vp; 2638 struct uio *uio = ap->a_uio; 2639 struct fuse_dispatcher fdi; 2640 struct fuse_getxattr_in *get_xattr_in; 2641 struct fuse_getxattr_out *get_xattr_out; 2642 struct mount *mp = vnode_mount(vp); 2643 struct thread *td = ap->a_td; 2644 struct ucred *cred = ap->a_cred; 2645 char *prefix; 2646 char *attr_str; 2647 size_t len; 2648 int err; 2649 2650 if (fuse_isdeadfs(vp)) 2651 return (EXTERROR(ENXIO, "This FUSE session is about " 2652 "to be closed")); 2653 2654 if (fsess_not_impl(mp, FUSE_GETXATTR)) 2655 return (EXTERROR(EOPNOTSUPP, "This server does not implement " 2656 "extended attributes")); 2657 2658 err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD); 2659 if (err) 2660 return err; 2661 2662 /* Default to looking for user attributes. */ 2663 if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) 2664 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING; 2665 else 2666 prefix = EXTATTR_NAMESPACE_USER_STRING; 2667 2668 len = strlen(prefix) + sizeof(extattr_namespace_separator) + 2669 strlen(ap->a_name) + 1; 2670 2671 fdisp_init(&fdi, len + sizeof(*get_xattr_in)); 2672 fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred); 2673 2674 get_xattr_in = fdi.indata; 2675 /* 2676 * Check to see whether we're querying the available size or 2677 * issuing the actual request. If we pass in 0, we get back struct 2678 * fuse_getxattr_out. If we pass in a non-zero size, we get back 2679 * that much data, without the struct fuse_getxattr_out header. 2680 */ 2681 if (uio == NULL) 2682 get_xattr_in->size = 0; 2683 else 2684 get_xattr_in->size = uio->uio_resid; 2685 2686 attr_str = (char *)fdi.indata + sizeof(*get_xattr_in); 2687 snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator, 2688 ap->a_name); 2689 2690 err = fdisp_wait_answ(&fdi); 2691 if (err != 0) { 2692 if (err == ENOSYS) { 2693 fsess_set_notimpl(mp, FUSE_GETXATTR); 2694 err = (EXTERROR(EOPNOTSUPP, "This server does not " 2695 "implement extended attributes")); 2696 } 2697 goto out; 2698 } 2699 2700 get_xattr_out = fdi.answ; 2701 2702 if (ap->a_size != NULL) 2703 *ap->a_size = get_xattr_out->size; 2704 2705 if (uio != NULL) 2706 err = uiomove(fdi.answ, fdi.iosize, uio); 2707 2708 out: 2709 fdisp_destroy(&fdi); 2710 return (err); 2711 } 2712 2713 /* 2714 struct vop_setextattr_args { 2715 struct vop_generic_args a_gen; 2716 struct vnode *a_vp; 2717 int a_attrnamespace; 2718 const char *a_name; 2719 struct uio *a_uio; 2720 struct ucred *a_cred; 2721 struct thread *a_td; 2722 }; 2723 */ 2724 static int 2725 fuse_vnop_setextattr(struct vop_setextattr_args *ap) 2726 { 2727 struct vnode *vp = ap->a_vp; 2728 struct uio *uio = ap->a_uio; 2729 struct fuse_dispatcher fdi; 2730 struct fuse_setxattr_in *set_xattr_in; 2731 struct mount *mp = vnode_mount(vp); 2732 struct thread *td = ap->a_td; 2733 struct ucred *cred = ap->a_cred; 2734 size_t struct_size = FUSE_COMPAT_SETXATTR_IN_SIZE; 2735 char *prefix; 2736 size_t len; 2737 char *attr_str; 2738 int err; 2739 2740 if (fuse_isdeadfs(vp)) 2741 return (EXTERROR(ENXIO, "This FUSE session is about " 2742 "to be closed")); 2743 2744 if (fsess_not_impl(mp, FUSE_SETXATTR)) 2745 return (EXTERROR(EOPNOTSUPP, "This server does not implement " 2746 "setting extended attributes")); 2747 2748 if (vfs_isrdonly(mp)) 2749 return EROFS; 2750 2751 /* Deleting xattrs must use VOP_DELETEEXTATTR instead */ 2752 if (ap->a_uio == NULL) { 2753 /* 2754 * If we got here as fallback from VOP_DELETEEXTATTR, then 2755 * return EOPNOTSUPP. 2756 */ 2757 if (fsess_not_impl(mp, FUSE_REMOVEXATTR)) 2758 return (EXTERROR(EOPNOTSUPP, "This server does not " 2759 "implement removing extended attributess")); 2760 else 2761 return (EXTERROR(EINVAL, "DELETEEXTATTR should be used " 2762 "to remove extattrs")); 2763 } 2764 2765 err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, 2766 VWRITE); 2767 if (err) 2768 return err; 2769 2770 /* Default to looking for user attributes. */ 2771 if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) 2772 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING; 2773 else 2774 prefix = EXTATTR_NAMESPACE_USER_STRING; 2775 2776 len = strlen(prefix) + sizeof(extattr_namespace_separator) + 2777 strlen(ap->a_name) + 1; 2778 2779 /* older FUSE servers use a smaller fuse_setxattr_in struct*/ 2780 if (fuse_libabi_geq(fuse_get_mpdata(mp), 7, 33)) 2781 struct_size = sizeof(*set_xattr_in); 2782 2783 fdisp_init(&fdi, len + struct_size + uio->uio_resid); 2784 fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred); 2785 2786 set_xattr_in = fdi.indata; 2787 set_xattr_in->size = uio->uio_resid; 2788 2789 if (fuse_libabi_geq(fuse_get_mpdata(mp), 7, 33)) { 2790 set_xattr_in->setxattr_flags = 0; 2791 set_xattr_in->padding = 0; 2792 } 2793 2794 attr_str = (char *)fdi.indata + struct_size; 2795 snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator, 2796 ap->a_name); 2797 2798 err = uiomove((char *)fdi.indata + struct_size + len, 2799 uio->uio_resid, uio); 2800 if (err != 0) { 2801 goto out; 2802 } 2803 2804 err = fdisp_wait_answ(&fdi); 2805 2806 if (err == ENOSYS) { 2807 fsess_set_notimpl(mp, FUSE_SETXATTR); 2808 err = EXTERROR(EOPNOTSUPP, "This server does not implement " 2809 "setting extended attributes"); 2810 } 2811 if (err == ERESTART) { 2812 /* Can't restart after calling uiomove */ 2813 err = EINTR; 2814 } 2815 2816 out: 2817 fdisp_destroy(&fdi); 2818 return (err); 2819 } 2820 2821 /* 2822 * The Linux / FUSE extended attribute list is simply a collection of 2823 * NUL-terminated strings. The FreeBSD extended attribute list is a single 2824 * byte length followed by a non-NUL terminated string. So, this allows 2825 * conversion of the Linux / FUSE format to the FreeBSD format in place. 2826 * Linux attribute names are reported with the namespace as a prefix (e.g. 2827 * "user.attribute_name"), but in FreeBSD they are reported without the 2828 * namespace prefix (e.g. "attribute_name"). So, we're going from: 2829 * 2830 * user.attr_name1\0user.attr_name2\0 2831 * 2832 * to: 2833 * 2834 * <num>attr_name1<num>attr_name2 2835 * 2836 * Where "<num>" is a single byte number of characters in the attribute name. 2837 * 2838 * Args: 2839 * prefix - exattr namespace prefix string 2840 * list, list_len - input list with namespace prefixes 2841 * bsd_list, bsd_list_len - output list compatible with bsd vfs 2842 */ 2843 static int 2844 fuse_xattrlist_convert(char *prefix, const char *list, int list_len, 2845 char *bsd_list, int *bsd_list_len) 2846 { 2847 int len, pos, dist_to_next, prefix_len; 2848 2849 pos = 0; 2850 *bsd_list_len = 0; 2851 prefix_len = strlen(prefix); 2852 2853 while (pos < list_len && list[pos] != '\0') { 2854 dist_to_next = strlen(&list[pos]) + 1; 2855 if (bcmp(&list[pos], prefix, prefix_len) == 0 && 2856 list[pos + prefix_len] == extattr_namespace_separator) { 2857 len = dist_to_next - 2858 (prefix_len + sizeof(extattr_namespace_separator)) - 1; 2859 if (len >= EXTATTR_MAXNAMELEN) 2860 return (ENAMETOOLONG); 2861 2862 bsd_list[*bsd_list_len] = len; 2863 memcpy(&bsd_list[*bsd_list_len + 1], 2864 &list[pos + prefix_len + 2865 sizeof(extattr_namespace_separator)], len); 2866 2867 *bsd_list_len += len + 1; 2868 } 2869 2870 pos += dist_to_next; 2871 } 2872 2873 return (0); 2874 } 2875 2876 /* 2877 * List extended attributes 2878 * 2879 * The FUSE_LISTXATTR operation is based on Linux's listxattr(2) syscall, which 2880 * has a number of differences compared to its FreeBSD equivalent, 2881 * extattr_list_file: 2882 * 2883 * - FUSE_LISTXATTR returns all extended attributes across all namespaces, 2884 * whereas listxattr(2) only returns attributes for a single namespace 2885 * - FUSE_LISTXATTR prepends each attribute name with "namespace." 2886 * - If the provided buffer is not large enough to hold the result, 2887 * FUSE_LISTXATTR should return ERANGE, whereas listxattr is expected to 2888 * return as many results as will fit. 2889 */ 2890 /* 2891 struct vop_listextattr_args { 2892 struct vop_generic_args a_gen; 2893 struct vnode *a_vp; 2894 int a_attrnamespace; 2895 struct uio *a_uio; 2896 size_t *a_size; 2897 struct ucred *a_cred; 2898 struct thread *a_td; 2899 }; 2900 */ 2901 static int 2902 fuse_vnop_listextattr(struct vop_listextattr_args *ap) 2903 { 2904 struct vnode *vp = ap->a_vp; 2905 struct uio *uio = ap->a_uio; 2906 struct fuse_dispatcher fdi; 2907 struct fuse_listxattr_in *list_xattr_in; 2908 struct fuse_listxattr_out *list_xattr_out; 2909 struct mount *mp = vnode_mount(vp); 2910 struct thread *td = ap->a_td; 2911 struct ucred *cred = ap->a_cred; 2912 char *prefix; 2913 char *bsd_list = NULL; 2914 char *linux_list; 2915 int bsd_list_len; 2916 int linux_list_len; 2917 int err; 2918 2919 if (fuse_isdeadfs(vp)) 2920 return (EXTERROR(ENXIO, "This FUSE session is about " 2921 "to be closed")); 2922 2923 if (fsess_not_impl(mp, FUSE_LISTXATTR)) 2924 return (EXTERROR(EOPNOTSUPP, "This server does not implement " 2925 "extended attributes")); 2926 2927 err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD); 2928 if (err) 2929 return err; 2930 2931 /* 2932 * Add space for a NUL and the period separator if enabled. 2933 * Default to looking for user attributes. 2934 */ 2935 if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) 2936 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING; 2937 else 2938 prefix = EXTATTR_NAMESPACE_USER_STRING; 2939 2940 fdisp_init(&fdi, sizeof(*list_xattr_in)); 2941 fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred); 2942 2943 /* 2944 * Retrieve Linux / FUSE compatible list size. 2945 */ 2946 list_xattr_in = fdi.indata; 2947 list_xattr_in->size = 0; 2948 2949 err = fdisp_wait_answ(&fdi); 2950 if (err != 0) { 2951 if (err == ENOSYS) { 2952 fsess_set_notimpl(mp, FUSE_LISTXATTR); 2953 err = EXTERROR(EOPNOTSUPP, "This server does not " 2954 "implement extended attributes"); 2955 } 2956 goto out; 2957 } 2958 2959 list_xattr_out = fdi.answ; 2960 linux_list_len = list_xattr_out->size; 2961 if (linux_list_len == 0) { 2962 if (ap->a_size != NULL) 2963 *ap->a_size = linux_list_len; 2964 goto out; 2965 } 2966 2967 /* 2968 * Retrieve Linux / FUSE compatible list values. 2969 */ 2970 fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred); 2971 list_xattr_in = fdi.indata; 2972 list_xattr_in->size = linux_list_len; 2973 2974 err = fdisp_wait_answ(&fdi); 2975 if (err == ERANGE) { 2976 /* 2977 * Race detected. The attribute list must've grown since the 2978 * first FUSE_LISTXATTR call. Start over. Go all the way back 2979 * to userland so we can process signals, if necessary, before 2980 * restarting. 2981 */ 2982 err = ERESTART; 2983 goto out; 2984 } else if (err != 0) 2985 goto out; 2986 2987 linux_list = fdi.answ; 2988 /* FUSE doesn't allow the server to return more data than requested */ 2989 if (fdi.iosize > linux_list_len) { 2990 struct fuse_data *data = fuse_get_mpdata(mp); 2991 2992 fuse_warn(data, FSESS_WARN_LSEXTATTR_LONG, 2993 "server returned " 2994 "more extended attribute data than requested; " 2995 "should've returned ERANGE instead."); 2996 } else { 2997 /* But returning less data is fine */ 2998 linux_list_len = fdi.iosize; 2999 } 3000 3001 /* 3002 * Retrieve the BSD compatible list values. 3003 * The Linux / FUSE attribute list format isn't the same 3004 * as FreeBSD's format. So we need to transform it into 3005 * FreeBSD's format before giving it to the user. 3006 */ 3007 bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK); 3008 err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len, 3009 bsd_list, &bsd_list_len); 3010 if (err != 0) 3011 goto out; 3012 3013 if (ap->a_size != NULL) 3014 *ap->a_size = bsd_list_len; 3015 3016 if (uio != NULL) 3017 err = uiomove(bsd_list, bsd_list_len, uio); 3018 3019 out: 3020 free(bsd_list, M_TEMP); 3021 fdisp_destroy(&fdi); 3022 return (err); 3023 } 3024 3025 /* 3026 struct vop_deallocate_args { 3027 struct vop_generic_args a_gen; 3028 struct vnode *a_vp; 3029 off_t *a_offset; 3030 off_t *a_len; 3031 int a_flags; 3032 int a_ioflag; 3033 struct ucred *a_cred; 3034 }; 3035 */ 3036 static int 3037 fuse_vnop_deallocate(struct vop_deallocate_args *ap) 3038 { 3039 struct vnode *vp = ap->a_vp; 3040 struct mount *mp = vnode_mount(vp); 3041 struct fuse_filehandle *fufh; 3042 struct fuse_dispatcher fdi; 3043 struct fuse_fallocate_in *ffi; 3044 struct ucred *cred = ap->a_cred; 3045 pid_t pid = curthread->td_proc->p_pid; 3046 off_t *len = ap->a_len; 3047 off_t *offset = ap->a_offset; 3048 int ioflag = ap->a_ioflag; 3049 off_t filesize; 3050 int err; 3051 bool closefufh = false; 3052 3053 if (fuse_isdeadfs(vp)) 3054 return (EXTERROR(ENXIO, "This FUSE session is about " 3055 "to be closed")); 3056 3057 if (vfs_isrdonly(mp)) 3058 return (EROFS); 3059 3060 if (fsess_not_impl(mp, FUSE_FALLOCATE)) 3061 goto fallback; 3062 3063 err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid); 3064 if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) { 3065 /* 3066 * nfsd will do I/O without first doing VOP_OPEN. We 3067 * must implicitly open the file here 3068 */ 3069 err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred); 3070 closefufh = true; 3071 } 3072 if (err) 3073 return (err); 3074 3075 fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE); 3076 3077 err = fuse_vnode_size(vp, &filesize, cred, curthread); 3078 if (err) 3079 goto out; 3080 fuse_inval_buf_range(vp, filesize, *offset, *offset + *len); 3081 3082 fdisp_init(&fdi, sizeof(*ffi)); 3083 fdisp_make_vp(&fdi, FUSE_FALLOCATE, vp, curthread, cred); 3084 ffi = fdi.indata; 3085 ffi->fh = fufh->fh_id; 3086 ffi->offset = *offset; 3087 ffi->length = *len; 3088 /* 3089 * FreeBSD's fspacectl is equivalent to Linux's fallocate with 3090 * mode == FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE 3091 */ 3092 ffi->mode = FUSE_FALLOC_FL_PUNCH_HOLE | FUSE_FALLOC_FL_KEEP_SIZE; 3093 err = fdisp_wait_answ(&fdi); 3094 3095 if (err == ENOSYS) { 3096 fdisp_destroy(&fdi); 3097 fsess_set_notimpl(mp, FUSE_FALLOCATE); 3098 goto fallback; 3099 } else if (err == EOPNOTSUPP) { 3100 /* 3101 * The file system server does not support FUSE_FALLOCATE with 3102 * the supplied mode for this particular file. 3103 */ 3104 fdisp_destroy(&fdi); 3105 goto fallback; 3106 } else if (!err) { 3107 /* 3108 * Clip the returned offset to EoF. Do it here rather than 3109 * before FUSE_FALLOCATE just in case the kernel's cached file 3110 * size is out of date. Unfortunately, FUSE does not return 3111 * any information about filesize from that operation. 3112 */ 3113 *offset = MIN(*offset + *len, filesize); 3114 *len = 0; 3115 fuse_vnode_undirty_cached_timestamps(vp, false); 3116 fuse_internal_clear_suid_on_write(vp, cred, curthread); 3117 3118 if (ioflag & IO_SYNC) 3119 err = fuse_internal_fsync(vp, curthread, MNT_WAIT, 3120 false); 3121 } 3122 3123 fdisp_destroy(&fdi); 3124 out: 3125 if (closefufh) 3126 fuse_filehandle_close(vp, fufh, curthread, cred); 3127 3128 return (err); 3129 3130 fallback: 3131 if (closefufh) 3132 fuse_filehandle_close(vp, fufh, curthread, cred); 3133 3134 return (vop_stddeallocate(ap)); 3135 } 3136 3137 /* 3138 struct vop_deleteextattr_args { 3139 struct vop_generic_args a_gen; 3140 struct vnode *a_vp; 3141 int a_attrnamespace; 3142 const char *a_name; 3143 struct ucred *a_cred; 3144 struct thread *a_td; 3145 }; 3146 */ 3147 static int 3148 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap) 3149 { 3150 struct vnode *vp = ap->a_vp; 3151 struct fuse_dispatcher fdi; 3152 struct mount *mp = vnode_mount(vp); 3153 struct thread *td = ap->a_td; 3154 struct ucred *cred = ap->a_cred; 3155 char *prefix; 3156 size_t len; 3157 char *attr_str; 3158 int err; 3159 3160 if (fuse_isdeadfs(vp)) 3161 return (EXTERROR(ENXIO, "This FUSE session is about " 3162 "to be closed")); 3163 3164 if (fsess_not_impl(mp, FUSE_REMOVEXATTR)) 3165 return (EXTERROR(EOPNOTSUPP, "This server does not implement " 3166 "removing extended attributes")); 3167 3168 if (vfs_isrdonly(mp)) 3169 return EROFS; 3170 3171 err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, 3172 VWRITE); 3173 if (err) 3174 return err; 3175 3176 /* Default to looking for user attributes. */ 3177 if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) 3178 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING; 3179 else 3180 prefix = EXTATTR_NAMESPACE_USER_STRING; 3181 3182 len = strlen(prefix) + sizeof(extattr_namespace_separator) + 3183 strlen(ap->a_name) + 1; 3184 3185 fdisp_init(&fdi, len); 3186 fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred); 3187 3188 attr_str = fdi.indata; 3189 snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator, 3190 ap->a_name); 3191 3192 err = fdisp_wait_answ(&fdi); 3193 if (err == ENOSYS) { 3194 fsess_set_notimpl(mp, FUSE_REMOVEXATTR); 3195 err = EXTERROR(EOPNOTSUPP, "This server does not implement " 3196 "removing extended attributes"); 3197 } 3198 3199 fdisp_destroy(&fdi); 3200 return (err); 3201 } 3202 3203 /* 3204 struct vnop_print_args { 3205 struct vnode *a_vp; 3206 }; 3207 */ 3208 static int 3209 fuse_vnop_print(struct vop_print_args *ap) 3210 { 3211 struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp); 3212 3213 printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n", 3214 (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid, 3215 (uintmax_t)fvdat->nlookup, 3216 fvdat->flag); 3217 3218 return 0; 3219 } 3220 3221 /* 3222 * Get an NFS filehandle for a FUSE file. 3223 * 3224 * This will only work for FUSE file systems that guarantee the uniqueness of 3225 * nodeid:generation, which most don't. 3226 */ 3227 /* 3228 vop_vptofh { 3229 IN struct vnode *a_vp; 3230 IN struct fid *a_fhp; 3231 }; 3232 */ 3233 static int 3234 fuse_vnop_vptofh(struct vop_vptofh_args *ap) 3235 { 3236 struct vnode *vp = ap->a_vp; 3237 struct fuse_vnode_data *fvdat = VTOFUD(vp); 3238 struct fuse_fid *fhp = (struct fuse_fid *)(ap->a_fhp); 3239 _Static_assert(sizeof(struct fuse_fid) <= sizeof(struct fid), 3240 "FUSE fid type is too big"); 3241 struct mount *mp = vnode_mount(vp); 3242 struct fuse_data *data = fuse_get_mpdata(mp); 3243 struct vattr va; 3244 int err; 3245 3246 if (!(data->dataflags & FSESS_EXPORT_SUPPORT)) { 3247 /* NFS requires lookups for "." and ".." */ 3248 SDT_PROBE2(fusefs, , vnops, trace, 1, 3249 "VOP_VPTOFH without FUSE_EXPORT_SUPPORT"); 3250 return (EXTERROR(EOPNOTSUPP, "This server is " 3251 "missing FUSE_EXPORT_SUPPORT")); 3252 } 3253 if ((mp->mnt_flag & MNT_EXPORTED) && 3254 fsess_is_impl(mp, FUSE_OPENDIR)) 3255 { 3256 /* 3257 * NFS is stateless, so nfsd must reopen a directory on every 3258 * call to VOP_READDIR, passing in the d_off field from the 3259 * final dirent of the previous invocation. But if the server 3260 * implements FUSE_OPENDIR, the FUSE protocol does not 3261 * guarantee that d_off will be valid after a directory is 3262 * closed and reopened. So prohibit exporting FUSE file 3263 * systems that implement FUSE_OPENDIR. 3264 * 3265 * But userspace NFS servers don't have this problem. 3266 */ 3267 SDT_PROBE2(fusefs, , vnops, trace, 1, 3268 "VOP_VPTOFH with FUSE_OPENDIR"); 3269 return (EXTERROR(EOPNOTSUPP, "This server implements " 3270 "FUSE_OPENDIR so is not compatible with getfh")); 3271 } 3272 3273 err = fuse_internal_getattr(vp, &va, curthread->td_ucred, curthread); 3274 if (err) 3275 return err; 3276 3277 /*ip = VTOI(ap->a_vp);*/ 3278 /*ufhp = (struct ufid *)ap->a_fhp;*/ 3279 fhp->len = sizeof(struct fuse_fid); 3280 fhp->nid = fvdat->nid; 3281 if (fvdat->generation <= UINT32_MAX) 3282 fhp->gen = fvdat->generation; 3283 else 3284 return (EXTERROR(EOVERFLOW, "inode generation " 3285 "number overflow")); 3286 return (0); 3287 } 3288