1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2007-2009 Google Inc. and Amit Singh 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following disclaimer 15 * in the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Google Inc. nor the names of its 18 * contributors may be used to endorse or promote products derived from 19 * this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Copyright (C) 2005 Csaba Henk. 34 * All rights reserved. 35 * 36 * Copyright (c) 2019 The FreeBSD Foundation 37 * 38 * Portions of this software were developed by BFF Storage Systems, LLC under 39 * sponsorship from the FreeBSD Foundation. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 50 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 */ 62 63 #include <sys/cdefs.h> 64 __FBSDID("$FreeBSD$"); 65 66 #include <sys/param.h> 67 #include <sys/systm.h> 68 #include <sys/counter.h> 69 #include <sys/module.h> 70 #include <sys/errno.h> 71 #include <sys/kernel.h> 72 #include <sys/conf.h> 73 #include <sys/uio.h> 74 #include <sys/malloc.h> 75 #include <sys/queue.h> 76 #include <sys/lock.h> 77 #include <sys/mutex.h> 78 #include <sys/sdt.h> 79 #include <sys/sx.h> 80 #include <sys/proc.h> 81 #include <sys/mount.h> 82 #include <sys/vnode.h> 83 #include <sys/namei.h> 84 #include <sys/stat.h> 85 #include <sys/unistd.h> 86 #include <sys/filedesc.h> 87 #include <sys/file.h> 88 #include <sys/fcntl.h> 89 #include <sys/dirent.h> 90 #include <sys/bio.h> 91 #include <sys/buf.h> 92 #include <sys/sysctl.h> 93 #include <sys/priv.h> 94 95 #include "fuse.h" 96 #include "fuse_file.h" 97 #include "fuse_internal.h" 98 #include "fuse_io.h" 99 #include "fuse_ipc.h" 100 #include "fuse_node.h" 101 #include "fuse_file.h" 102 103 SDT_PROVIDER_DECLARE(fusefs); 104 /* 105 * Fuse trace probe: 106 * arg0: verbosity. Higher numbers give more verbose messages 107 * arg1: Textual message 108 */ 109 SDT_PROBE_DEFINE2(fusefs, , internal, trace, "int", "char*"); 110 111 #ifdef ZERO_PAD_INCOMPLETE_BUFS 112 static int isbzero(void *buf, size_t len); 113 114 #endif 115 116 counter_u64_t fuse_lookup_cache_hits; 117 counter_u64_t fuse_lookup_cache_misses; 118 119 SYSCTL_COUNTER_U64(_vfs_fusefs_stats, OID_AUTO, lookup_cache_hits, CTLFLAG_RD, 120 &fuse_lookup_cache_hits, "number of positive cache hits in lookup"); 121 122 SYSCTL_COUNTER_U64(_vfs_fusefs_stats, OID_AUTO, lookup_cache_misses, CTLFLAG_RD, 123 &fuse_lookup_cache_misses, "number of cache misses in lookup"); 124 125 int 126 fuse_internal_get_cached_vnode(struct mount* mp, ino_t ino, int flags, 127 struct vnode **vpp) 128 { 129 struct bintime now; 130 struct thread *td = curthread; 131 uint64_t nodeid = ino; 132 int error; 133 134 *vpp = NULL; 135 136 error = vfs_hash_get(mp, fuse_vnode_hash(nodeid), flags, td, vpp, 137 fuse_vnode_cmp, &nodeid); 138 if (error) 139 return error; 140 /* 141 * Check the entry cache timeout. We have to do this within fusefs 142 * instead of by using cache_enter_time/cache_lookup because those 143 * routines are only intended to work with pathnames, not inodes 144 */ 145 if (*vpp != NULL) { 146 getbinuptime(&now); 147 if (bintime_cmp(&(VTOFUD(*vpp)->entry_cache_timeout), &now, >)){ 148 counter_u64_add(fuse_lookup_cache_hits, 1); 149 return 0; 150 } else { 151 /* Entry cache timeout */ 152 counter_u64_add(fuse_lookup_cache_misses, 1); 153 cache_purge(*vpp); 154 vput(*vpp); 155 *vpp = NULL; 156 } 157 } 158 return 0; 159 } 160 161 SDT_PROBE_DEFINE0(fusefs, , internal, access_vadmin); 162 /* Synchronously send a FUSE_ACCESS operation */ 163 int 164 fuse_internal_access(struct vnode *vp, 165 accmode_t mode, 166 struct thread *td, 167 struct ucred *cred) 168 { 169 int err = 0; 170 uint32_t mask = F_OK; 171 int dataflags; 172 struct mount *mp; 173 struct fuse_dispatcher fdi; 174 struct fuse_access_in *fai; 175 struct fuse_data *data; 176 177 mp = vnode_mount(vp); 178 179 data = fuse_get_mpdata(mp); 180 dataflags = data->dataflags; 181 182 if (mode == 0) 183 return 0; 184 185 if (mode & VMODIFY_PERMS && vfs_isrdonly(mp)) { 186 switch (vp->v_type) { 187 case VDIR: 188 /* FALLTHROUGH */ 189 case VLNK: 190 /* FALLTHROUGH */ 191 case VREG: 192 return EROFS; 193 default: 194 break; 195 } 196 } 197 198 /* Unless explicitly permitted, deny everyone except the fs owner. */ 199 if (!(dataflags & FSESS_DAEMON_CAN_SPY)) { 200 if (fuse_match_cred(data->daemoncred, cred)) 201 return EPERM; 202 } 203 204 if (dataflags & FSESS_DEFAULT_PERMISSIONS) { 205 struct vattr va; 206 207 fuse_internal_getattr(vp, &va, cred, td); 208 return vaccess(vp->v_type, va.va_mode, va.va_uid, 209 va.va_gid, mode, cred); 210 } 211 212 if (mode & VADMIN) { 213 /* 214 * The FUSE protocol doesn't have an equivalent of VADMIN, so 215 * it's a bug if we ever reach this point with that bit set. 216 */ 217 SDT_PROBE0(fusefs, , internal, access_vadmin); 218 } 219 220 if (fsess_not_impl(mp, FUSE_ACCESS)) 221 return 0; 222 223 if ((mode & (VWRITE | VAPPEND)) != 0) 224 mask |= W_OK; 225 if ((mode & VREAD) != 0) 226 mask |= R_OK; 227 if ((mode & VEXEC) != 0) 228 mask |= X_OK; 229 230 fdisp_init(&fdi, sizeof(*fai)); 231 fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred); 232 233 fai = fdi.indata; 234 fai->mask = mask; 235 236 err = fdisp_wait_answ(&fdi); 237 fdisp_destroy(&fdi); 238 239 if (err == ENOSYS) { 240 fsess_set_notimpl(mp, FUSE_ACCESS); 241 err = 0; 242 } 243 return err; 244 } 245 246 /* 247 * Cache FUSE attributes from attr, in attribute cache associated with vnode 248 * 'vp'. Optionally, if argument 'vap' is not NULL, store a copy of the 249 * converted attributes there as well. 250 * 251 * If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do 252 * return the result to the caller). 253 */ 254 void 255 fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr, 256 uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap, 257 bool from_server) 258 { 259 struct mount *mp; 260 struct fuse_vnode_data *fvdat; 261 struct fuse_data *data; 262 struct vattr *vp_cache_at; 263 264 mp = vnode_mount(vp); 265 fvdat = VTOFUD(vp); 266 data = fuse_get_mpdata(mp); 267 268 ASSERT_VOP_ELOCKED(vp, "fuse_internal_cache_attrs"); 269 270 fuse_validity_2_bintime(attr_valid, attr_valid_nsec, 271 &fvdat->attr_cache_timeout); 272 273 if (vnode_isreg(vp) && 274 fvdat->cached_attrs.va_size != VNOVAL && 275 attr->size != fvdat->cached_attrs.va_size) 276 { 277 if ( data->cache_mode == FUSE_CACHE_WB && 278 fvdat->flag & FN_SIZECHANGE) 279 { 280 const char *msg; 281 282 /* 283 * The server changed the file's size even though we're 284 * using writeback cacheing and and we have outstanding 285 * dirty writes! That's a server bug. 286 */ 287 if (fuse_libabi_geq(data, 7, 23)) { 288 msg = "writeback cache incoherent!." 289 "To prevent data corruption, disable " 290 "the writeback cache according to your " 291 "FUSE server's documentation."; 292 } else { 293 msg = "writeback cache incoherent!." 294 "To prevent data corruption, disable " 295 "the writeback cache by setting " 296 "vfs.fusefs.data_cache_mode to 0 or 1."; 297 } 298 fuse_warn(data, FSESS_WARN_WB_CACHE_INCOHERENT, msg); 299 } 300 if (fuse_vnode_attr_cache_valid(vp) && 301 data->cache_mode != FUSE_CACHE_UC) 302 { 303 /* 304 * The server changed the file's size even though we 305 * have it cached and our cache has not yet expired. 306 * That's a bug. 307 */ 308 fuse_warn(data, FSESS_WARN_CACHE_INCOHERENT, 309 "cache incoherent! " 310 "To prevent " 311 "data corruption, disable the data cache " 312 "by mounting with -o direct_io, or as " 313 "directed otherwise by your FUSE server's " 314 "documentation."); 315 } 316 } 317 318 /* Fix our buffers if the filesize changed without us knowing */ 319 if (vnode_isreg(vp) && attr->size != fvdat->cached_attrs.va_size) { 320 (void)fuse_vnode_setsize(vp, attr->size, from_server); 321 fvdat->cached_attrs.va_size = attr->size; 322 } 323 324 if (attr_valid > 0 || attr_valid_nsec > 0) 325 vp_cache_at = &(fvdat->cached_attrs); 326 else if (vap != NULL) 327 vp_cache_at = vap; 328 else 329 return; 330 331 vattr_null(vp_cache_at); 332 vp_cache_at->va_fsid = mp->mnt_stat.f_fsid.val[0]; 333 vp_cache_at->va_fileid = attr->ino; 334 vp_cache_at->va_mode = attr->mode & ~S_IFMT; 335 vp_cache_at->va_nlink = attr->nlink; 336 vp_cache_at->va_uid = attr->uid; 337 vp_cache_at->va_gid = attr->gid; 338 vp_cache_at->va_rdev = attr->rdev; 339 vp_cache_at->va_size = attr->size; 340 /* XXX on i386, seconds are truncated to 32 bits */ 341 vp_cache_at->va_atime.tv_sec = attr->atime; 342 vp_cache_at->va_atime.tv_nsec = attr->atimensec; 343 vp_cache_at->va_mtime.tv_sec = attr->mtime; 344 vp_cache_at->va_mtime.tv_nsec = attr->mtimensec; 345 vp_cache_at->va_ctime.tv_sec = attr->ctime; 346 vp_cache_at->va_ctime.tv_nsec = attr->ctimensec; 347 if (fuse_libabi_geq(data, 7, 9) && attr->blksize > 0) 348 vp_cache_at->va_blocksize = attr->blksize; 349 else 350 vp_cache_at->va_blocksize = PAGE_SIZE; 351 vp_cache_at->va_type = IFTOVT(attr->mode); 352 vp_cache_at->va_bytes = attr->blocks * S_BLKSIZE; 353 vp_cache_at->va_flags = 0; 354 355 if (vap != vp_cache_at && vap != NULL) 356 memcpy(vap, vp_cache_at, sizeof(*vap)); 357 } 358 359 /* fsync */ 360 361 int 362 fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio) 363 { 364 if (tick->tk_aw_ohead.error == ENOSYS) { 365 fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick)); 366 } 367 return 0; 368 } 369 370 int 371 fuse_internal_fsync(struct vnode *vp, 372 struct thread *td, 373 int waitfor, 374 bool datasync) 375 { 376 struct fuse_fsync_in *ffsi = NULL; 377 struct fuse_dispatcher fdi; 378 struct fuse_filehandle *fufh; 379 struct fuse_vnode_data *fvdat = VTOFUD(vp); 380 struct mount *mp = vnode_mount(vp); 381 int op = FUSE_FSYNC; 382 int err = 0; 383 384 if (fsess_not_impl(vnode_mount(vp), 385 (vnode_vtype(vp) == VDIR ? FUSE_FSYNCDIR : FUSE_FSYNC))) { 386 return 0; 387 } 388 if (vnode_isdir(vp)) 389 op = FUSE_FSYNCDIR; 390 391 if (fsess_not_impl(mp, op)) 392 return 0; 393 394 fdisp_init(&fdi, sizeof(*ffsi)); 395 /* 396 * fsync every open file handle for this file, because we can't be sure 397 * which file handle the caller is really referring to. 398 */ 399 LIST_FOREACH(fufh, &fvdat->handles, next) { 400 fdi.iosize = sizeof(*ffsi); 401 if (ffsi == NULL) 402 fdisp_make_vp(&fdi, op, vp, td, NULL); 403 else 404 fdisp_refresh_vp(&fdi, op, vp, td, NULL); 405 ffsi = fdi.indata; 406 ffsi->fh = fufh->fh_id; 407 ffsi->fsync_flags = 0; 408 409 if (datasync) 410 ffsi->fsync_flags = FUSE_FSYNC_FDATASYNC; 411 412 if (waitfor == MNT_WAIT) { 413 err = fdisp_wait_answ(&fdi); 414 } else { 415 fuse_insert_callback(fdi.tick, 416 fuse_internal_fsync_callback); 417 fuse_insert_message(fdi.tick, false); 418 } 419 if (err == ENOSYS) { 420 /* ENOSYS means "success, and don't call again" */ 421 fsess_set_notimpl(mp, op); 422 err = 0; 423 break; 424 } 425 } 426 fdisp_destroy(&fdi); 427 428 return err; 429 } 430 431 /* Asynchronous invalidation */ 432 SDT_PROBE_DEFINE3(fusefs, , internal, invalidate_entry, 433 "struct vnode*", "struct fuse_notify_inval_entry_out*", "char*"); 434 int 435 fuse_internal_invalidate_entry(struct mount *mp, struct uio *uio) 436 { 437 struct fuse_notify_inval_entry_out fnieo; 438 struct componentname cn; 439 struct vnode *dvp, *vp; 440 char name[PATH_MAX]; 441 int err; 442 443 if ((err = uiomove(&fnieo, sizeof(fnieo), uio)) != 0) 444 return (err); 445 446 if (fnieo.namelen >= sizeof(name)) 447 return (EINVAL); 448 449 if ((err = uiomove(name, fnieo.namelen, uio)) != 0) 450 return (err); 451 name[fnieo.namelen] = '\0'; 452 /* fusefs does not cache "." or ".." entries */ 453 if (strncmp(name, ".", sizeof(".")) == 0 || 454 strncmp(name, "..", sizeof("..")) == 0) 455 return (0); 456 457 if (fnieo.parent == FUSE_ROOT_ID) 458 err = VFS_ROOT(mp, LK_SHARED, &dvp); 459 else 460 err = fuse_internal_get_cached_vnode( mp, fnieo.parent, 461 LK_SHARED, &dvp); 462 SDT_PROBE3(fusefs, , internal, invalidate_entry, dvp, &fnieo, name); 463 /* 464 * If dvp is not in the cache, then it must've been reclaimed. And 465 * since fuse_vnop_reclaim does a cache_purge, name's entry must've 466 * been invalidated already. So we can safely return if dvp == NULL 467 */ 468 if (err != 0 || dvp == NULL) 469 return (err); 470 /* 471 * XXX we can't check dvp's generation because the FUSE invalidate 472 * entry message doesn't include it. Worse case is that we invalidate 473 * an entry that didn't need to be invalidated. 474 */ 475 476 cn.cn_nameiop = LOOKUP; 477 cn.cn_flags = 0; /* !MAKEENTRY means free cached entry */ 478 cn.cn_cred = curthread->td_ucred; 479 cn.cn_lkflags = LK_SHARED; 480 cn.cn_pnbuf = NULL; 481 cn.cn_nameptr = name; 482 cn.cn_namelen = fnieo.namelen; 483 err = cache_lookup(dvp, &vp, &cn, NULL, NULL); 484 MPASS(err == 0); 485 fuse_vnode_clear_attr_cache(dvp); 486 vput(dvp); 487 return (0); 488 } 489 490 SDT_PROBE_DEFINE2(fusefs, , internal, invalidate_inode, 491 "struct vnode*", "struct fuse_notify_inval_inode_out *"); 492 int 493 fuse_internal_invalidate_inode(struct mount *mp, struct uio *uio) 494 { 495 struct fuse_notify_inval_inode_out fniio; 496 struct vnode *vp; 497 int err; 498 499 if ((err = uiomove(&fniio, sizeof(fniio), uio)) != 0) 500 return (err); 501 502 if (fniio.ino == FUSE_ROOT_ID) 503 err = VFS_ROOT(mp, LK_EXCLUSIVE, &vp); 504 else 505 err = fuse_internal_get_cached_vnode(mp, fniio.ino, LK_SHARED, 506 &vp); 507 SDT_PROBE2(fusefs, , internal, invalidate_inode, vp, &fniio); 508 if (err != 0 || vp == NULL) 509 return (err); 510 /* 511 * XXX we can't check vp's generation because the FUSE invalidate 512 * entry message doesn't include it. Worse case is that we invalidate 513 * an inode that didn't need to be invalidated. 514 */ 515 516 /* 517 * Flush and invalidate buffers if off >= 0. Technically we only need 518 * to flush and invalidate the range of offsets [off, off + len), but 519 * for simplicity's sake we do everything. 520 */ 521 if (fniio.off >= 0) 522 fuse_io_invalbuf(vp, curthread); 523 fuse_vnode_clear_attr_cache(vp); 524 vput(vp); 525 return (0); 526 } 527 528 /* mknod */ 529 int 530 fuse_internal_mknod(struct vnode *dvp, struct vnode **vpp, 531 struct componentname *cnp, struct vattr *vap) 532 { 533 struct fuse_data *data; 534 struct fuse_mknod_in fmni; 535 size_t insize; 536 537 data = fuse_get_mpdata(dvp->v_mount); 538 539 fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode); 540 fmni.rdev = vap->va_rdev; 541 if (fuse_libabi_geq(data, 7, 12)) { 542 insize = sizeof(fmni); 543 fmni.umask = curthread->td_proc->p_pd->pd_cmask; 544 } else { 545 insize = FUSE_COMPAT_MKNOD_IN_SIZE; 546 } 547 return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni, 548 insize, vap->va_type)); 549 } 550 551 /* readdir */ 552 553 int 554 fuse_internal_readdir(struct vnode *vp, 555 struct uio *uio, 556 struct fuse_filehandle *fufh, 557 struct fuse_iov *cookediov, 558 int *ncookies, 559 uint64_t *cookies) 560 { 561 int err = 0; 562 struct fuse_dispatcher fdi; 563 struct fuse_read_in *fri = NULL; 564 565 if (uio_resid(uio) == 0) 566 return 0; 567 fdisp_init(&fdi, 0); 568 569 /* 570 * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p 571 * I/O). 572 */ 573 while (uio_resid(uio) > 0) { 574 fdi.iosize = sizeof(*fri); 575 fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); 576 fri = fdi.indata; 577 fri->fh = fufh->fh_id; 578 fri->offset = uio_offset(uio); 579 fri->size = MIN(uio->uio_resid, 580 fuse_get_mpdata(vp->v_mount)->max_read); 581 582 if ((err = fdisp_wait_answ(&fdi))) 583 break; 584 if ((err = fuse_internal_readdir_processdata(uio, fri->size, 585 fdi.answ, fdi.iosize, cookediov, ncookies, &cookies))) 586 break; 587 } 588 589 fdisp_destroy(&fdi); 590 return ((err == -1) ? 0 : err); 591 } 592 593 /* 594 * Return -1 to indicate that this readdir is finished, 0 if it copied 595 * all the directory data read in and it may be possible to read more 596 * and greater than 0 for a failure. 597 */ 598 int 599 fuse_internal_readdir_processdata(struct uio *uio, 600 size_t reqsize, 601 void *buf, 602 size_t bufsize, 603 struct fuse_iov *cookediov, 604 int *ncookies, 605 uint64_t **cookiesp) 606 { 607 int err = 0; 608 int oreclen; 609 size_t freclen; 610 611 struct dirent *de; 612 struct fuse_dirent *fudge; 613 uint64_t *cookies; 614 615 cookies = *cookiesp; 616 if (bufsize < FUSE_NAME_OFFSET) 617 return -1; 618 for (;;) { 619 if (bufsize < FUSE_NAME_OFFSET) { 620 err = -1; 621 break; 622 } 623 fudge = (struct fuse_dirent *)buf; 624 freclen = FUSE_DIRENT_SIZE(fudge); 625 626 if (bufsize < freclen) { 627 /* 628 * This indicates a partial directory entry at the 629 * end of the directory data. 630 */ 631 err = -1; 632 break; 633 } 634 #ifdef ZERO_PAD_INCOMPLETE_BUFS 635 if (isbzero(buf, FUSE_NAME_OFFSET)) { 636 err = -1; 637 break; 638 } 639 #endif 640 641 if (!fudge->namelen || fudge->namelen > MAXNAMLEN) { 642 err = EINVAL; 643 break; 644 } 645 oreclen = GENERIC_DIRSIZ((struct pseudo_dirent *) 646 &fudge->namelen); 647 648 if (oreclen > uio_resid(uio)) { 649 /* Out of space for the dir so we are done. */ 650 err = -1; 651 break; 652 } 653 fiov_adjust(cookediov, oreclen); 654 bzero(cookediov->base, oreclen); 655 656 de = (struct dirent *)cookediov->base; 657 de->d_fileno = fudge->ino; 658 de->d_off = fudge->off; 659 de->d_reclen = oreclen; 660 de->d_type = fudge->type; 661 de->d_namlen = fudge->namelen; 662 memcpy((char *)cookediov->base + sizeof(struct dirent) - 663 MAXNAMLEN - 1, 664 (char *)buf + FUSE_NAME_OFFSET, fudge->namelen); 665 dirent_terminate(de); 666 667 err = uiomove(cookediov->base, cookediov->len, uio); 668 if (err) 669 break; 670 if (cookies != NULL) { 671 if (*ncookies == 0) { 672 err = -1; 673 break; 674 } 675 *cookies = fudge->off; 676 cookies++; 677 (*ncookies)--; 678 } 679 buf = (char *)buf + freclen; 680 bufsize -= freclen; 681 uio_setoffset(uio, fudge->off); 682 } 683 *cookiesp = cookies; 684 685 return err; 686 } 687 688 /* remove */ 689 690 int 691 fuse_internal_remove(struct vnode *dvp, 692 struct vnode *vp, 693 struct componentname *cnp, 694 enum fuse_opcode op) 695 { 696 struct fuse_dispatcher fdi; 697 nlink_t nlink; 698 int err = 0; 699 700 fdisp_init(&fdi, cnp->cn_namelen + 1); 701 fdisp_make_vp(&fdi, op, dvp, curthread, cnp->cn_cred); 702 703 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 704 ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 705 706 err = fdisp_wait_answ(&fdi); 707 fdisp_destroy(&fdi); 708 709 if (err) 710 return (err); 711 712 /* 713 * Access the cached nlink even if the attr cached has expired. If 714 * it's inaccurate, the worst that will happen is: 715 * 1) We'll recycle the vnode even though the file has another link we 716 * don't know about, costing a bit of cpu time, or 717 * 2) We won't recycle the vnode even though all of its links are gone. 718 * It will linger around until vnlru reclaims it, costing a bit of 719 * temporary memory. 720 */ 721 nlink = VTOFUD(vp)->cached_attrs.va_nlink--; 722 723 /* 724 * Purge the parent's attribute cache because the daemon 725 * should've updated its mtime and ctime. 726 */ 727 fuse_vnode_clear_attr_cache(dvp); 728 729 /* NB: nlink could be zero if it was never cached */ 730 if (nlink <= 1 || vnode_vtype(vp) == VDIR) { 731 fuse_internal_vnode_disappear(vp); 732 } else { 733 cache_purge(vp); 734 fuse_vnode_update(vp, FN_CTIMECHANGE); 735 } 736 737 return err; 738 } 739 740 /* rename */ 741 742 int 743 fuse_internal_rename(struct vnode *fdvp, 744 struct componentname *fcnp, 745 struct vnode *tdvp, 746 struct componentname *tcnp) 747 { 748 struct fuse_dispatcher fdi; 749 struct fuse_rename_in *fri; 750 int err = 0; 751 752 fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2); 753 fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, curthread, tcnp->cn_cred); 754 755 fri = fdi.indata; 756 fri->newdir = VTOI(tdvp); 757 memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr, 758 fcnp->cn_namelen); 759 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0'; 760 memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1, 761 tcnp->cn_nameptr, tcnp->cn_namelen); 762 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen + 763 tcnp->cn_namelen + 1] = '\0'; 764 765 err = fdisp_wait_answ(&fdi); 766 fdisp_destroy(&fdi); 767 return err; 768 } 769 770 /* strategy */ 771 772 /* entity creation */ 773 774 void 775 fuse_internal_newentry_makerequest(struct mount *mp, 776 uint64_t dnid, 777 struct componentname *cnp, 778 enum fuse_opcode op, 779 void *buf, 780 size_t bufsize, 781 struct fuse_dispatcher *fdip) 782 { 783 fdip->iosize = bufsize + cnp->cn_namelen + 1; 784 785 fdisp_make(fdip, op, mp, dnid, curthread, cnp->cn_cred); 786 memcpy(fdip->indata, buf, bufsize); 787 memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen); 788 ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0'; 789 } 790 791 int 792 fuse_internal_newentry_core(struct vnode *dvp, 793 struct vnode **vpp, 794 struct componentname *cnp, 795 enum vtype vtyp, 796 struct fuse_dispatcher *fdip) 797 { 798 int err = 0; 799 struct fuse_entry_out *feo; 800 struct mount *mp = vnode_mount(dvp); 801 802 if ((err = fdisp_wait_answ(fdip))) { 803 return err; 804 } 805 feo = fdip->answ; 806 807 if ((err = fuse_internal_checkentry(feo, vtyp))) { 808 return err; 809 } 810 err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vtyp); 811 if (err) { 812 fuse_internal_forget_send(mp, curthread, cnp->cn_cred, 813 feo->nodeid, 1); 814 return err; 815 } 816 817 /* 818 * Purge the parent's attribute cache because the daemon should've 819 * updated its mtime and ctime 820 */ 821 fuse_vnode_clear_attr_cache(dvp); 822 823 fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid, 824 feo->attr_valid_nsec, NULL, true); 825 826 return err; 827 } 828 829 int 830 fuse_internal_newentry(struct vnode *dvp, 831 struct vnode **vpp, 832 struct componentname *cnp, 833 enum fuse_opcode op, 834 void *buf, 835 size_t bufsize, 836 enum vtype vtype) 837 { 838 int err; 839 struct fuse_dispatcher fdi; 840 struct mount *mp = vnode_mount(dvp); 841 842 fdisp_init(&fdi, 0); 843 fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf, 844 bufsize, &fdi); 845 err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi); 846 fdisp_destroy(&fdi); 847 848 return err; 849 } 850 851 /* entity destruction */ 852 853 int 854 fuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio) 855 { 856 fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL, 857 ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1); 858 859 return 0; 860 } 861 862 void 863 fuse_internal_forget_send(struct mount *mp, 864 struct thread *td, 865 struct ucred *cred, 866 uint64_t nodeid, 867 uint64_t nlookup) 868 { 869 870 struct fuse_dispatcher fdi; 871 struct fuse_forget_in *ffi; 872 873 /* 874 * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu", 875 * (long long unsigned) nodeid)); 876 */ 877 878 fdisp_init(&fdi, sizeof(*ffi)); 879 fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred); 880 881 ffi = fdi.indata; 882 ffi->nlookup = nlookup; 883 884 fuse_insert_message(fdi.tick, false); 885 fdisp_destroy(&fdi); 886 } 887 888 /* Fetch the vnode's attributes from the daemon*/ 889 int 890 fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap, 891 struct ucred *cred, struct thread *td) 892 { 893 struct fuse_dispatcher fdi; 894 struct fuse_vnode_data *fvdat = VTOFUD(vp); 895 struct fuse_getattr_in *fgai; 896 struct fuse_attr_out *fao; 897 off_t old_filesize = fvdat->cached_attrs.va_size; 898 struct timespec old_atime = fvdat->cached_attrs.va_atime; 899 struct timespec old_ctime = fvdat->cached_attrs.va_ctime; 900 struct timespec old_mtime = fvdat->cached_attrs.va_mtime; 901 enum vtype vtyp; 902 int err; 903 904 ASSERT_VOP_LOCKED(vp, __func__); 905 906 fdisp_init(&fdi, sizeof(*fgai)); 907 fdisp_make_vp(&fdi, FUSE_GETATTR, vp, td, cred); 908 fgai = fdi.indata; 909 /* 910 * We could look up a file handle and set it in fgai->fh, but that 911 * involves extra runtime work and I'm unaware of any file systems that 912 * care. 913 */ 914 fgai->getattr_flags = 0; 915 if ((err = fdisp_wait_answ(&fdi))) { 916 if (err == ENOENT) 917 fuse_internal_vnode_disappear(vp); 918 goto out; 919 } 920 921 fao = (struct fuse_attr_out *)fdi.answ; 922 vtyp = IFTOVT(fao->attr.mode); 923 if (fvdat->flag & FN_SIZECHANGE) 924 fao->attr.size = old_filesize; 925 if (fvdat->flag & FN_ATIMECHANGE) { 926 fao->attr.atime = old_atime.tv_sec; 927 fao->attr.atimensec = old_atime.tv_nsec; 928 } 929 if (fvdat->flag & FN_CTIMECHANGE) { 930 fao->attr.ctime = old_ctime.tv_sec; 931 fao->attr.ctimensec = old_ctime.tv_nsec; 932 } 933 if (fvdat->flag & FN_MTIMECHANGE) { 934 fao->attr.mtime = old_mtime.tv_sec; 935 fao->attr.mtimensec = old_mtime.tv_nsec; 936 } 937 fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid, 938 fao->attr_valid_nsec, vap, true); 939 if (vtyp != vnode_vtype(vp)) { 940 fuse_internal_vnode_disappear(vp); 941 err = ENOENT; 942 } 943 944 out: 945 fdisp_destroy(&fdi); 946 return err; 947 } 948 949 /* Read a vnode's attributes from cache or fetch them from the fuse daemon */ 950 int 951 fuse_internal_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred, 952 struct thread *td) 953 { 954 struct vattr *attrs; 955 956 if ((attrs = VTOVA(vp)) != NULL) { 957 *vap = *attrs; /* struct copy */ 958 return 0; 959 } 960 961 return fuse_internal_do_getattr(vp, vap, cred, td); 962 } 963 964 void 965 fuse_internal_vnode_disappear(struct vnode *vp) 966 { 967 struct fuse_vnode_data *fvdat = VTOFUD(vp); 968 969 ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear"); 970 fvdat->flag |= FN_REVOKED; 971 cache_purge(vp); 972 } 973 974 /* fuse start/stop */ 975 976 SDT_PROBE_DEFINE2(fusefs, , internal, init_done, 977 "struct fuse_data*", "struct fuse_init_out*"); 978 int 979 fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio) 980 { 981 int err = 0; 982 struct fuse_data *data = tick->tk_data; 983 struct fuse_init_out *fiio; 984 985 if ((err = tick->tk_aw_ohead.error)) { 986 goto out; 987 } 988 if ((err = fticket_pull(tick, uio))) { 989 goto out; 990 } 991 fiio = fticket_resp(tick)->base; 992 993 data->fuse_libabi_major = fiio->major; 994 data->fuse_libabi_minor = fiio->minor; 995 if (!fuse_libabi_geq(data, 7, 4)) { 996 /* 997 * With a little work we could support servers as old as 7.1. 998 * But there would be little payoff. 999 */ 1000 SDT_PROBE2(fusefs, , internal, trace, 1, 1001 "userpace version too low"); 1002 err = EPROTONOSUPPORT; 1003 goto out; 1004 } 1005 1006 if (fuse_libabi_geq(data, 7, 5)) { 1007 if (fticket_resp(tick)->len == sizeof(struct fuse_init_out) || 1008 fticket_resp(tick)->len == FUSE_COMPAT_22_INIT_OUT_SIZE) { 1009 data->max_write = fiio->max_write; 1010 if (fiio->flags & FUSE_ASYNC_READ) 1011 data->dataflags |= FSESS_ASYNC_READ; 1012 if (fiio->flags & FUSE_POSIX_LOCKS) 1013 data->dataflags |= FSESS_POSIX_LOCKS; 1014 if (fiio->flags & FUSE_EXPORT_SUPPORT) 1015 data->dataflags |= FSESS_EXPORT_SUPPORT; 1016 if (fiio->flags & FUSE_NO_OPEN_SUPPORT) 1017 data->dataflags |= FSESS_NO_OPEN_SUPPORT; 1018 if (fiio->flags & FUSE_NO_OPENDIR_SUPPORT) 1019 data->dataflags |= FSESS_NO_OPENDIR_SUPPORT; 1020 /* 1021 * Don't bother to check FUSE_BIG_WRITES, because it's 1022 * redundant with max_write 1023 */ 1024 /* 1025 * max_background and congestion_threshold are not 1026 * implemented 1027 */ 1028 } else { 1029 err = EINVAL; 1030 } 1031 } else { 1032 /* Old fixed values */ 1033 data->max_write = 4096; 1034 } 1035 1036 if (fuse_libabi_geq(data, 7, 6)) 1037 data->max_readahead_blocks = fiio->max_readahead / maxbcachebuf; 1038 1039 if (!fuse_libabi_geq(data, 7, 7)) 1040 fsess_set_notimpl(data->mp, FUSE_INTERRUPT); 1041 1042 if (!fuse_libabi_geq(data, 7, 8)) { 1043 fsess_set_notimpl(data->mp, FUSE_BMAP); 1044 fsess_set_notimpl(data->mp, FUSE_DESTROY); 1045 } 1046 1047 if (!fuse_libabi_geq(data, 7, 19)) { 1048 fsess_set_notimpl(data->mp, FUSE_FALLOCATE); 1049 } 1050 1051 if (fuse_libabi_geq(data, 7, 23) && fiio->time_gran >= 1 && 1052 fiio->time_gran <= 1000000000) 1053 data->time_gran = fiio->time_gran; 1054 else 1055 data->time_gran = 1; 1056 1057 if (!fuse_libabi_geq(data, 7, 23)) 1058 data->cache_mode = fuse_data_cache_mode; 1059 else if (fiio->flags & FUSE_WRITEBACK_CACHE) 1060 data->cache_mode = FUSE_CACHE_WB; 1061 else 1062 data->cache_mode = FUSE_CACHE_WT; 1063 1064 if (!fuse_libabi_geq(data, 7, 24)) 1065 fsess_set_notimpl(data->mp, FUSE_LSEEK); 1066 1067 if (!fuse_libabi_geq(data, 7, 28)) 1068 fsess_set_notimpl(data->mp, FUSE_COPY_FILE_RANGE); 1069 1070 out: 1071 if (err) { 1072 fdata_set_dead(data); 1073 } 1074 FUSE_LOCK(); 1075 data->dataflags |= FSESS_INITED; 1076 SDT_PROBE2(fusefs, , internal, init_done, data, fiio); 1077 wakeup(&data->ticketer); 1078 FUSE_UNLOCK(); 1079 1080 return 0; 1081 } 1082 1083 void 1084 fuse_internal_send_init(struct fuse_data *data, struct thread *td) 1085 { 1086 struct fuse_init_in *fiii; 1087 struct fuse_dispatcher fdi; 1088 1089 fdisp_init(&fdi, sizeof(*fiii)); 1090 fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL); 1091 fiii = fdi.indata; 1092 fiii->major = FUSE_KERNEL_VERSION; 1093 fiii->minor = FUSE_KERNEL_MINOR_VERSION; 1094 /* 1095 * fusefs currently reads ahead no more than one cache block at a time. 1096 * See fuse_read_biobackend 1097 */ 1098 fiii->max_readahead = maxbcachebuf; 1099 /* 1100 * Unsupported features: 1101 * FUSE_FILE_OPS: No known FUSE server or client supports it 1102 * FUSE_ATOMIC_O_TRUNC: our VFS cannot support it 1103 * FUSE_DONT_MASK: unlike Linux, FreeBSD always applies the umask, even 1104 * when default ACLs are in use. 1105 * FUSE_SPLICE_WRITE, FUSE_SPLICE_MOVE, FUSE_SPLICE_READ: FreeBSD 1106 * doesn't have splice(2). 1107 * FUSE_FLOCK_LOCKS: not yet implemented 1108 * FUSE_HAS_IOCTL_DIR: not yet implemented 1109 * FUSE_AUTO_INVAL_DATA: not yet implemented 1110 * FUSE_DO_READDIRPLUS: not yet implemented 1111 * FUSE_READDIRPLUS_AUTO: not yet implemented 1112 * FUSE_ASYNC_DIO: not yet implemented 1113 * FUSE_PARALLEL_DIROPS: not yet implemented 1114 * FUSE_HANDLE_KILLPRIV: not yet implemented 1115 * FUSE_POSIX_ACL: not yet implemented 1116 * FUSE_ABORT_ERROR: not yet implemented 1117 * FUSE_CACHE_SYMLINKS: not yet implemented 1118 * FUSE_MAX_PAGES: not yet implemented 1119 */ 1120 fiii->flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_EXPORT_SUPPORT 1121 | FUSE_BIG_WRITES | FUSE_WRITEBACK_CACHE 1122 | FUSE_NO_OPEN_SUPPORT | FUSE_NO_OPENDIR_SUPPORT; 1123 1124 fuse_insert_callback(fdi.tick, fuse_internal_init_callback); 1125 fuse_insert_message(fdi.tick, false); 1126 fdisp_destroy(&fdi); 1127 } 1128 1129 /* 1130 * Send a FUSE_SETATTR operation with no permissions checks. If cred is NULL, 1131 * send the request with root credentials 1132 */ 1133 int fuse_internal_setattr(struct vnode *vp, struct vattr *vap, 1134 struct thread *td, struct ucred *cred) 1135 { 1136 struct fuse_vnode_data *fvdat; 1137 struct fuse_dispatcher fdi; 1138 struct fuse_setattr_in *fsai; 1139 struct mount *mp; 1140 pid_t pid = td->td_proc->p_pid; 1141 struct fuse_data *data; 1142 int err = 0; 1143 enum vtype vtyp; 1144 1145 ASSERT_VOP_ELOCKED(vp, __func__); 1146 1147 mp = vnode_mount(vp); 1148 fvdat = VTOFUD(vp); 1149 data = fuse_get_mpdata(mp); 1150 1151 fdisp_init(&fdi, sizeof(*fsai)); 1152 fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred); 1153 if (!cred) { 1154 fdi.finh->uid = 0; 1155 fdi.finh->gid = 0; 1156 } 1157 fsai = fdi.indata; 1158 fsai->valid = 0; 1159 1160 if (vap->va_uid != (uid_t)VNOVAL) { 1161 fsai->uid = vap->va_uid; 1162 fsai->valid |= FATTR_UID; 1163 } 1164 if (vap->va_gid != (gid_t)VNOVAL) { 1165 fsai->gid = vap->va_gid; 1166 fsai->valid |= FATTR_GID; 1167 } 1168 if (vap->va_size != VNOVAL) { 1169 struct fuse_filehandle *fufh = NULL; 1170 1171 /*Truncate to a new value. */ 1172 fsai->size = vap->va_size; 1173 fsai->valid |= FATTR_SIZE; 1174 1175 fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid); 1176 if (fufh) { 1177 fsai->fh = fufh->fh_id; 1178 fsai->valid |= FATTR_FH; 1179 } 1180 VTOFUD(vp)->flag &= ~FN_SIZECHANGE; 1181 } 1182 if (vap->va_atime.tv_sec != VNOVAL) { 1183 fsai->atime = vap->va_atime.tv_sec; 1184 fsai->atimensec = vap->va_atime.tv_nsec; 1185 fsai->valid |= FATTR_ATIME; 1186 if (vap->va_vaflags & VA_UTIMES_NULL) 1187 fsai->valid |= FATTR_ATIME_NOW; 1188 } else if (fvdat->flag & FN_ATIMECHANGE) { 1189 fsai->atime = fvdat->cached_attrs.va_atime.tv_sec; 1190 fsai->atimensec = fvdat->cached_attrs.va_atime.tv_nsec; 1191 fsai->valid |= FATTR_ATIME; 1192 } 1193 if (vap->va_mtime.tv_sec != VNOVAL) { 1194 fsai->mtime = vap->va_mtime.tv_sec; 1195 fsai->mtimensec = vap->va_mtime.tv_nsec; 1196 fsai->valid |= FATTR_MTIME; 1197 if (vap->va_vaflags & VA_UTIMES_NULL) 1198 fsai->valid |= FATTR_MTIME_NOW; 1199 } else if (fvdat->flag & FN_MTIMECHANGE) { 1200 fsai->mtime = fvdat->cached_attrs.va_mtime.tv_sec; 1201 fsai->mtimensec = fvdat->cached_attrs.va_mtime.tv_nsec; 1202 fsai->valid |= FATTR_MTIME; 1203 } 1204 if (fuse_libabi_geq(data, 7, 23) && fvdat->flag & FN_CTIMECHANGE) { 1205 fsai->ctime = fvdat->cached_attrs.va_ctime.tv_sec; 1206 fsai->ctimensec = fvdat->cached_attrs.va_ctime.tv_nsec; 1207 fsai->valid |= FATTR_CTIME; 1208 } 1209 if (vap->va_mode != (mode_t)VNOVAL) { 1210 fsai->mode = vap->va_mode & ALLPERMS; 1211 fsai->valid |= FATTR_MODE; 1212 } 1213 if (!fsai->valid) { 1214 goto out; 1215 } 1216 1217 if ((err = fdisp_wait_answ(&fdi))) 1218 goto out; 1219 vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode); 1220 1221 if (vnode_vtype(vp) != vtyp) { 1222 if (vnode_vtype(vp) == VNON && vtyp != VNON) { 1223 SDT_PROBE2(fusefs, , internal, trace, 1, "FUSE: Dang! " 1224 "vnode_vtype is VNON and vtype isn't."); 1225 } else { 1226 /* 1227 * STALE vnode, ditch 1228 * 1229 * The vnode has changed its type "behind our back". 1230 * This probably means that the file got deleted and 1231 * recreated on the server, with the same inode. 1232 * There's nothing really we can do, so let us just 1233 * return ENOENT. After all, the entry must not have 1234 * existed in the recent past. If the user tries 1235 * again, it will work. 1236 */ 1237 fuse_internal_vnode_disappear(vp); 1238 err = ENOENT; 1239 } 1240 } 1241 if (err == 0) { 1242 struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ; 1243 fuse_vnode_undirty_cached_timestamps(vp, true); 1244 fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid, 1245 fao->attr_valid_nsec, NULL, false); 1246 getnanouptime(&fvdat->last_local_modify); 1247 } 1248 1249 out: 1250 fdisp_destroy(&fdi); 1251 return err; 1252 } 1253 1254 /* 1255 * FreeBSD clears the SUID and SGID bits on any write by a non-root user. 1256 */ 1257 void 1258 fuse_internal_clear_suid_on_write(struct vnode *vp, struct ucred *cred, 1259 struct thread *td) 1260 { 1261 struct fuse_data *data; 1262 struct mount *mp; 1263 struct vattr va; 1264 int dataflags; 1265 1266 mp = vnode_mount(vp); 1267 data = fuse_get_mpdata(mp); 1268 dataflags = data->dataflags; 1269 1270 ASSERT_VOP_LOCKED(vp, __func__); 1271 1272 if (dataflags & FSESS_DEFAULT_PERMISSIONS) { 1273 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) { 1274 fuse_internal_getattr(vp, &va, cred, td); 1275 if (va.va_mode & (S_ISUID | S_ISGID)) { 1276 mode_t mode = va.va_mode & ~(S_ISUID | S_ISGID); 1277 /* Clear all vattr fields except mode */ 1278 vattr_null(&va); 1279 va.va_mode = mode; 1280 1281 /* 1282 * Ignore fuse_internal_setattr's return value, 1283 * because at this point the write operation has 1284 * already succeeded and we don't want to return 1285 * failing status for that. 1286 */ 1287 (void)fuse_internal_setattr(vp, &va, td, NULL); 1288 } 1289 } 1290 } 1291 } 1292 1293 #ifdef ZERO_PAD_INCOMPLETE_BUFS 1294 static int 1295 isbzero(void *buf, size_t len) 1296 { 1297 int i; 1298 1299 for (i = 0; i < len; i++) { 1300 if (((char *)buf)[i]) 1301 return (0); 1302 } 1303 1304 return (1); 1305 } 1306 1307 #endif 1308 1309 void 1310 fuse_internal_init(void) 1311 { 1312 fuse_lookup_cache_misses = counter_u64_alloc(M_WAITOK); 1313 fuse_lookup_cache_hits = counter_u64_alloc(M_WAITOK); 1314 } 1315 1316 void 1317 fuse_internal_destroy(void) 1318 { 1319 counter_u64_free(fuse_lookup_cache_hits); 1320 counter_u64_free(fuse_lookup_cache_misses); 1321 } 1322