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 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 #include <sys/cdefs.h> 59 __FBSDID("$FreeBSD$"); 60 61 #include <sys/param.h> 62 #include <sys/module.h> 63 #include <sys/systm.h> 64 #include <sys/errno.h> 65 #include <sys/kernel.h> 66 #include <sys/conf.h> 67 #include <sys/uio.h> 68 #include <sys/malloc.h> 69 #include <sys/queue.h> 70 #include <sys/lock.h> 71 #include <sys/mutex.h> 72 #include <sys/sdt.h> 73 #include <sys/sx.h> 74 #include <sys/proc.h> 75 #include <sys/mount.h> 76 #include <sys/vnode.h> 77 #include <sys/namei.h> 78 #include <sys/stat.h> 79 #include <sys/unistd.h> 80 #include <sys/filedesc.h> 81 #include <sys/file.h> 82 #include <sys/fcntl.h> 83 #include <sys/dirent.h> 84 #include <sys/bio.h> 85 #include <sys/buf.h> 86 #include <sys/sysctl.h> 87 #include <sys/priv.h> 88 89 #include "fuse.h" 90 #include "fuse_file.h" 91 #include "fuse_internal.h" 92 #include "fuse_ipc.h" 93 #include "fuse_node.h" 94 #include "fuse_file.h" 95 96 SDT_PROVIDER_DECLARE(fusefs); 97 /* 98 * Fuse trace probe: 99 * arg0: verbosity. Higher numbers give more verbose messages 100 * arg1: Textual message 101 */ 102 SDT_PROBE_DEFINE2(fusefs, , internal, trace, "int", "char*"); 103 104 #ifdef ZERO_PAD_INCOMPLETE_BUFS 105 static int isbzero(void *buf, size_t len); 106 107 #endif 108 109 /* Synchronously send a FUSE_ACCESS operation */ 110 int 111 fuse_internal_access(struct vnode *vp, 112 accmode_t mode, 113 struct thread *td, 114 struct ucred *cred) 115 { 116 int err = 0; 117 uint32_t mask = F_OK; 118 int dataflags; 119 int vtype; 120 struct mount *mp; 121 struct fuse_dispatcher fdi; 122 struct fuse_access_in *fai; 123 struct fuse_data *data; 124 125 mp = vnode_mount(vp); 126 vtype = vnode_vtype(vp); 127 128 data = fuse_get_mpdata(mp); 129 dataflags = data->dataflags; 130 131 if (mode == 0) 132 return 0; 133 134 if (mode & VMODIFY_PERMS && vfs_isrdonly(mp)) { 135 switch (vp->v_type) { 136 case VDIR: 137 /* FALLTHROUGH */ 138 case VLNK: 139 /* FALLTHROUGH */ 140 case VREG: 141 return EROFS; 142 default: 143 break; 144 } 145 } 146 147 /* Unless explicitly permitted, deny everyone except the fs owner. */ 148 if (!(dataflags & FSESS_DAEMON_CAN_SPY)) { 149 if (fuse_match_cred(data->daemoncred, cred)) 150 return EPERM; 151 } 152 153 if (dataflags & FSESS_DEFAULT_PERMISSIONS) { 154 struct vattr va; 155 156 fuse_internal_getattr(vp, &va, cred, td); 157 return vaccess(vp->v_type, va.va_mode, va.va_uid, 158 va.va_gid, mode, cred, NULL); 159 } 160 161 if (!fsess_isimpl(mp, FUSE_ACCESS)) 162 return 0; 163 164 if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) 165 mask |= W_OK; 166 if ((mode & VREAD) != 0) 167 mask |= R_OK; 168 if ((mode & VEXEC) != 0) 169 mask |= X_OK; 170 171 fdisp_init(&fdi, sizeof(*fai)); 172 fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred); 173 174 fai = fdi.indata; 175 fai->mask = mask; 176 177 err = fdisp_wait_answ(&fdi); 178 fdisp_destroy(&fdi); 179 180 if (err == ENOSYS) { 181 fsess_set_notimpl(mp, FUSE_ACCESS); 182 err = 0; 183 } 184 return err; 185 } 186 187 /* 188 * Cache FUSE attributes from attr, in attribute cache associated with vnode 189 * 'vp'. Optionally, if argument 'vap' is not NULL, store a copy of the 190 * converted attributes there as well. 191 * 192 * If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do 193 * return the result to the caller). 194 */ 195 void 196 fuse_internal_cache_attrs(struct vnode *vp, struct ucred *cred, 197 struct fuse_attr *attr, uint64_t attr_valid, uint32_t attr_valid_nsec, 198 struct vattr *vap) 199 { 200 struct mount *mp; 201 struct fuse_vnode_data *fvdat; 202 struct fuse_data *data; 203 struct vattr *vp_cache_at; 204 205 mp = vnode_mount(vp); 206 fvdat = VTOFUD(vp); 207 data = fuse_get_mpdata(mp); 208 if (!cred) 209 cred = curthread->td_ucred; 210 211 ASSERT_VOP_ELOCKED(vp, "fuse_internal_cache_attrs"); 212 213 fuse_validity_2_bintime(attr_valid, attr_valid_nsec, 214 &fvdat->attr_cache_timeout); 215 216 /* Fix our buffers if the filesize changed without us knowing */ 217 if (vnode_isreg(vp) && attr->size != fvdat->cached_attrs.va_size) { 218 (void)fuse_vnode_setsize(vp, cred, attr->size); 219 fvdat->cached_attrs.va_size = attr->size; 220 } 221 222 if (attr_valid > 0 || attr_valid_nsec > 0) 223 vp_cache_at = &(fvdat->cached_attrs); 224 else if (vap != NULL) 225 vp_cache_at = vap; 226 else 227 return; 228 229 vattr_null(vp_cache_at); 230 vp_cache_at->va_fsid = mp->mnt_stat.f_fsid.val[0]; 231 vp_cache_at->va_fileid = attr->ino; 232 vp_cache_at->va_mode = attr->mode & ~S_IFMT; 233 vp_cache_at->va_nlink = attr->nlink; 234 vp_cache_at->va_uid = attr->uid; 235 vp_cache_at->va_gid = attr->gid; 236 vp_cache_at->va_rdev = attr->rdev; 237 vp_cache_at->va_size = attr->size; 238 /* XXX on i386, seconds are truncated to 32 bits */ 239 vp_cache_at->va_atime.tv_sec = attr->atime; 240 vp_cache_at->va_atime.tv_nsec = attr->atimensec; 241 vp_cache_at->va_mtime.tv_sec = attr->mtime; 242 vp_cache_at->va_mtime.tv_nsec = attr->mtimensec; 243 vp_cache_at->va_ctime.tv_sec = attr->ctime; 244 vp_cache_at->va_ctime.tv_nsec = attr->ctimensec; 245 if (fuse_libabi_geq(data, 7, 9) && attr->blksize > 0) 246 vp_cache_at->va_blocksize = attr->blksize; 247 else 248 vp_cache_at->va_blocksize = PAGE_SIZE; 249 vp_cache_at->va_type = IFTOVT(attr->mode); 250 vp_cache_at->va_bytes = attr->blocks * S_BLKSIZE; 251 vp_cache_at->va_flags = 0; 252 253 if (vap != vp_cache_at && vap != NULL) 254 memcpy(vap, vp_cache_at, sizeof(*vap)); 255 } 256 257 258 /* fsync */ 259 260 int 261 fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio) 262 { 263 if (tick->tk_aw_ohead.error == ENOSYS) { 264 fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick)); 265 } 266 return 0; 267 } 268 269 int 270 fuse_internal_fsync(struct vnode *vp, 271 struct thread *td, 272 int waitfor, 273 bool datasync) 274 { 275 struct fuse_fsync_in *ffsi = NULL; 276 struct fuse_dispatcher fdi; 277 struct fuse_filehandle *fufh; 278 struct fuse_vnode_data *fvdat = VTOFUD(vp); 279 struct mount *mp = vnode_mount(vp); 280 int op = FUSE_FSYNC; 281 int err = 0; 282 283 if (!fsess_isimpl(vnode_mount(vp), 284 (vnode_vtype(vp) == VDIR ? FUSE_FSYNCDIR : FUSE_FSYNC))) { 285 return 0; 286 } 287 if (vnode_isdir(vp)) 288 op = FUSE_FSYNCDIR; 289 290 if (!fsess_isimpl(mp, op)) 291 return 0; 292 293 fdisp_init(&fdi, sizeof(*ffsi)); 294 /* 295 * fsync every open file handle for this file, because we can't be sure 296 * which file handle the caller is really referring to. 297 */ 298 LIST_FOREACH(fufh, &fvdat->handles, next) { 299 if (ffsi == NULL) 300 fdisp_make_vp(&fdi, op, vp, td, NULL); 301 else 302 fdisp_refresh_vp(&fdi, op, vp, td, NULL); 303 ffsi = fdi.indata; 304 ffsi->fh = fufh->fh_id; 305 ffsi->fsync_flags = 0; 306 307 if (datasync) 308 ffsi->fsync_flags = 1; 309 310 if (waitfor == MNT_WAIT) { 311 err = fdisp_wait_answ(&fdi); 312 } else { 313 fuse_insert_callback(fdi.tick, 314 fuse_internal_fsync_callback); 315 fuse_insert_message(fdi.tick, false); 316 } 317 if (err == ENOSYS) { 318 /* ENOSYS means "success, and don't call again" */ 319 fsess_set_notimpl(mp, op); 320 err = 0; 321 break; 322 } 323 } 324 fdisp_destroy(&fdi); 325 326 return err; 327 } 328 329 /* mknod */ 330 int 331 fuse_internal_mknod(struct vnode *dvp, struct vnode **vpp, 332 struct componentname *cnp, struct vattr *vap) 333 { 334 struct fuse_mknod_in fmni; 335 336 fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode); 337 fmni.rdev = vap->va_rdev; 338 return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni, 339 sizeof(fmni), vap->va_type)); 340 } 341 342 /* readdir */ 343 344 int 345 fuse_internal_readdir(struct vnode *vp, 346 struct uio *uio, 347 off_t startoff, 348 struct fuse_filehandle *fufh, 349 struct fuse_iov *cookediov, 350 int *ncookies, 351 u_long *cookies) 352 { 353 int err = 0; 354 struct fuse_dispatcher fdi; 355 struct fuse_read_in *fri = NULL; 356 int fnd_start; 357 358 if (uio_resid(uio) == 0) 359 return 0; 360 fdisp_init(&fdi, 0); 361 362 /* 363 * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p 364 * I/O). 365 */ 366 367 /* 368 * fnd_start is set non-zero once the offset in the directory gets 369 * to the startoff. This is done because directories must be read 370 * from the beginning (offset == 0) when fuse_vnop_readdir() needs 371 * to do an open of the directory. 372 * If it is not set non-zero here, it will be set non-zero in 373 * fuse_internal_readdir_processdata() when uio_offset == startoff. 374 */ 375 fnd_start = 0; 376 if (uio->uio_offset == startoff) 377 fnd_start = 1; 378 while (uio_resid(uio) > 0) { 379 fdi.iosize = sizeof(*fri); 380 if (fri == NULL) 381 fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); 382 else 383 fdisp_refresh_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); 384 385 fri = fdi.indata; 386 fri->fh = fufh->fh_id; 387 fri->offset = uio_offset(uio); 388 fri->size = MIN(uio->uio_resid, 389 fuse_get_mpdata(vp->v_mount)->max_read); 390 391 if ((err = fdisp_wait_answ(&fdi))) 392 break; 393 if ((err = fuse_internal_readdir_processdata(uio, startoff, 394 &fnd_start, fri->size, fdi.answ, fdi.iosize, cookediov, 395 ncookies, &cookies))) 396 break; 397 } 398 399 fdisp_destroy(&fdi); 400 return ((err == -1) ? 0 : err); 401 } 402 403 /* 404 * Return -1 to indicate that this readdir is finished, 0 if it copied 405 * all the directory data read in and it may be possible to read more 406 * and greater than 0 for a failure. 407 */ 408 int 409 fuse_internal_readdir_processdata(struct uio *uio, 410 off_t startoff, 411 int *fnd_start, 412 size_t reqsize, 413 void *buf, 414 size_t bufsize, 415 struct fuse_iov *cookediov, 416 int *ncookies, 417 u_long **cookiesp) 418 { 419 int err = 0; 420 int bytesavail; 421 size_t freclen; 422 423 struct dirent *de; 424 struct fuse_dirent *fudge; 425 u_long *cookies; 426 427 cookies = *cookiesp; 428 if (bufsize < FUSE_NAME_OFFSET) 429 return -1; 430 for (;;) { 431 if (bufsize < FUSE_NAME_OFFSET) { 432 err = -1; 433 break; 434 } 435 fudge = (struct fuse_dirent *)buf; 436 freclen = FUSE_DIRENT_SIZE(fudge); 437 438 if (bufsize < freclen) { 439 /* 440 * This indicates a partial directory entry at the 441 * end of the directory data. 442 */ 443 err = -1; 444 break; 445 } 446 #ifdef ZERO_PAD_INCOMPLETE_BUFS 447 if (isbzero(buf, FUSE_NAME_OFFSET)) { 448 err = -1; 449 break; 450 } 451 #endif 452 453 if (!fudge->namelen || fudge->namelen > MAXNAMLEN) { 454 err = EINVAL; 455 break; 456 } 457 bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *) 458 &fudge->namelen); 459 460 if (bytesavail > uio_resid(uio)) { 461 /* Out of space for the dir so we are done. */ 462 err = -1; 463 break; 464 } 465 /* 466 * Don't start to copy the directory entries out until 467 * the requested offset in the directory is found. 468 */ 469 if (*fnd_start != 0) { 470 fiov_adjust(cookediov, bytesavail); 471 bzero(cookediov->base, bytesavail); 472 473 de = (struct dirent *)cookediov->base; 474 de->d_fileno = fudge->ino; 475 de->d_reclen = bytesavail; 476 de->d_type = fudge->type; 477 de->d_namlen = fudge->namelen; 478 memcpy((char *)cookediov->base + sizeof(struct dirent) - 479 MAXNAMLEN - 1, 480 (char *)buf + FUSE_NAME_OFFSET, fudge->namelen); 481 dirent_terminate(de); 482 483 err = uiomove(cookediov->base, cookediov->len, uio); 484 if (err) 485 break; 486 if (cookies != NULL) { 487 if (*ncookies == 0) { 488 err = -1; 489 break; 490 } 491 *cookies = fudge->off; 492 cookies++; 493 (*ncookies)--; 494 } 495 } else if (startoff == fudge->off) 496 *fnd_start = 1; 497 buf = (char *)buf + freclen; 498 bufsize -= freclen; 499 uio_setoffset(uio, fudge->off); 500 } 501 *cookiesp = cookies; 502 503 return err; 504 } 505 506 /* remove */ 507 508 int 509 fuse_internal_remove(struct vnode *dvp, 510 struct vnode *vp, 511 struct componentname *cnp, 512 enum fuse_opcode op) 513 { 514 struct fuse_dispatcher fdi; 515 int err = 0; 516 517 fdisp_init(&fdi, cnp->cn_namelen + 1); 518 fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred); 519 520 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 521 ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 522 523 err = fdisp_wait_answ(&fdi); 524 fdisp_destroy(&fdi); 525 return err; 526 } 527 528 /* rename */ 529 530 int 531 fuse_internal_rename(struct vnode *fdvp, 532 struct componentname *fcnp, 533 struct vnode *tdvp, 534 struct componentname *tcnp) 535 { 536 struct fuse_dispatcher fdi; 537 struct fuse_rename_in *fri; 538 int err = 0; 539 540 fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2); 541 fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred); 542 543 fri = fdi.indata; 544 fri->newdir = VTOI(tdvp); 545 memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr, 546 fcnp->cn_namelen); 547 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0'; 548 memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1, 549 tcnp->cn_nameptr, tcnp->cn_namelen); 550 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen + 551 tcnp->cn_namelen + 1] = '\0'; 552 553 err = fdisp_wait_answ(&fdi); 554 fdisp_destroy(&fdi); 555 return err; 556 } 557 558 /* strategy */ 559 560 /* entity creation */ 561 562 void 563 fuse_internal_newentry_makerequest(struct mount *mp, 564 uint64_t dnid, 565 struct componentname *cnp, 566 enum fuse_opcode op, 567 void *buf, 568 size_t bufsize, 569 struct fuse_dispatcher *fdip) 570 { 571 fdip->iosize = bufsize + cnp->cn_namelen + 1; 572 573 fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred); 574 memcpy(fdip->indata, buf, bufsize); 575 memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen); 576 ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0'; 577 } 578 579 int 580 fuse_internal_newentry_core(struct vnode *dvp, 581 struct vnode **vpp, 582 struct componentname *cnp, 583 enum vtype vtyp, 584 struct fuse_dispatcher *fdip) 585 { 586 int err = 0; 587 struct fuse_entry_out *feo; 588 struct mount *mp = vnode_mount(dvp); 589 590 if ((err = fdisp_wait_answ(fdip))) { 591 return err; 592 } 593 feo = fdip->answ; 594 595 if ((err = fuse_internal_checkentry(feo, vtyp))) { 596 return err; 597 } 598 err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vtyp); 599 if (err) { 600 fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred, 601 feo->nodeid, 1); 602 return err; 603 } 604 605 /* 606 * Purge the parent's attribute cache because the daemon should've 607 * updated its mtime and ctime 608 */ 609 fuse_vnode_clear_attr_cache(dvp); 610 611 fuse_internal_cache_attrs(*vpp, NULL, &feo->attr, feo->attr_valid, 612 feo->attr_valid_nsec, NULL); 613 614 return err; 615 } 616 617 int 618 fuse_internal_newentry(struct vnode *dvp, 619 struct vnode **vpp, 620 struct componentname *cnp, 621 enum fuse_opcode op, 622 void *buf, 623 size_t bufsize, 624 enum vtype vtype) 625 { 626 int err; 627 struct fuse_dispatcher fdi; 628 struct mount *mp = vnode_mount(dvp); 629 630 fdisp_init(&fdi, 0); 631 fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf, 632 bufsize, &fdi); 633 err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi); 634 fdisp_destroy(&fdi); 635 636 return err; 637 } 638 639 /* entity destruction */ 640 641 int 642 fuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio) 643 { 644 fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL, 645 ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1); 646 647 return 0; 648 } 649 650 void 651 fuse_internal_forget_send(struct mount *mp, 652 struct thread *td, 653 struct ucred *cred, 654 uint64_t nodeid, 655 uint64_t nlookup) 656 { 657 658 struct fuse_dispatcher fdi; 659 struct fuse_forget_in *ffi; 660 661 /* 662 * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu", 663 * (long long unsigned) nodeid)); 664 */ 665 666 fdisp_init(&fdi, sizeof(*ffi)); 667 fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred); 668 669 ffi = fdi.indata; 670 ffi->nlookup = nlookup; 671 672 fuse_insert_message(fdi.tick, false); 673 fdisp_destroy(&fdi); 674 } 675 676 /* Fetch the vnode's attributes from the daemon*/ 677 int 678 fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap, 679 struct ucred *cred, struct thread *td) 680 { 681 struct fuse_dispatcher fdi; 682 struct fuse_vnode_data *fvdat = VTOFUD(vp); 683 struct fuse_attr_out *fao; 684 off_t old_filesize = fvdat->cached_attrs.va_size; 685 enum vtype vtyp; 686 int err; 687 688 fdisp_init(&fdi, 0); 689 if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) { 690 if (err == ENOENT) 691 fuse_internal_vnode_disappear(vp); 692 goto out; 693 } 694 695 fao = (struct fuse_attr_out *)fdi.answ; 696 vtyp = IFTOVT(fao->attr.mode); 697 if (fvdat->flag & FN_SIZECHANGE) 698 fao->attr.size = old_filesize; 699 fuse_internal_cache_attrs(vp, NULL, &fao->attr, fao->attr_valid, 700 fao->attr_valid_nsec, vap); 701 if (vtyp != vnode_vtype(vp)) { 702 fuse_internal_vnode_disappear(vp); 703 err = ENOENT; 704 } 705 706 out: 707 fdisp_destroy(&fdi); 708 return err; 709 } 710 711 /* Read a vnode's attributes from cache or fetch them from the fuse daemon */ 712 int 713 fuse_internal_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred, 714 struct thread *td) 715 { 716 struct vattr *attrs; 717 718 if ((attrs = VTOVA(vp)) != NULL) { 719 *vap = *attrs; /* struct copy */ 720 return 0; 721 } 722 723 return fuse_internal_do_getattr(vp, vap, cred, td); 724 } 725 726 void 727 fuse_internal_vnode_disappear(struct vnode *vp) 728 { 729 struct fuse_vnode_data *fvdat = VTOFUD(vp); 730 731 ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear"); 732 fvdat->flag |= FN_REVOKED; 733 bintime_clear(&fvdat->attr_cache_timeout); 734 cache_purge(vp); 735 } 736 737 /* fuse start/stop */ 738 739 int 740 fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio) 741 { 742 int err = 0; 743 struct fuse_data *data = tick->tk_data; 744 struct fuse_init_out *fiio; 745 746 if ((err = tick->tk_aw_ohead.error)) { 747 goto out; 748 } 749 if ((err = fticket_pull(tick, uio))) { 750 goto out; 751 } 752 fiio = fticket_resp(tick)->base; 753 754 /* XXX: Do we want to check anything further besides this? */ 755 if (fiio->major < 7) { 756 SDT_PROBE2(fusefs, , internal, trace, 1, 757 "userpace version too low"); 758 err = EPROTONOSUPPORT; 759 goto out; 760 } 761 data->fuse_libabi_major = fiio->major; 762 data->fuse_libabi_minor = fiio->minor; 763 764 if (fuse_libabi_geq(data, 7, 5)) { 765 if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) { 766 data->max_write = fiio->max_write; 767 if (fiio->flags & FUSE_ASYNC_READ) 768 data->dataflags |= FSESS_ASYNC_READ; 769 if (fiio->flags & FUSE_POSIX_LOCKS) 770 data->dataflags |= FSESS_POSIX_LOCKS; 771 if (fiio->flags & FUSE_EXPORT_SUPPORT) 772 data->dataflags |= FSESS_EXPORT_SUPPORT; 773 } else { 774 err = EINVAL; 775 } 776 } else { 777 /* Old fix values */ 778 data->max_write = 4096; 779 } 780 781 out: 782 if (err) { 783 fdata_set_dead(data); 784 } 785 FUSE_LOCK(); 786 data->dataflags |= FSESS_INITED; 787 wakeup(&data->ticketer); 788 FUSE_UNLOCK(); 789 790 return 0; 791 } 792 793 void 794 fuse_internal_send_init(struct fuse_data *data, struct thread *td) 795 { 796 struct fuse_init_in *fiii; 797 struct fuse_dispatcher fdi; 798 799 fdisp_init(&fdi, sizeof(*fiii)); 800 fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL); 801 fiii = fdi.indata; 802 fiii->major = FUSE_KERNEL_VERSION; 803 fiii->minor = FUSE_KERNEL_MINOR_VERSION; 804 /* 805 * fusefs currently doesn't do any readahead other than fetching whole 806 * buffer cache block sized regions at once. So the max readahead is 807 * the size of a buffer cache block. 808 */ 809 fiii->max_readahead = maxbcachebuf; 810 fiii->flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_EXPORT_SUPPORT ; 811 812 fuse_insert_callback(fdi.tick, fuse_internal_init_callback); 813 fuse_insert_message(fdi.tick, false); 814 fdisp_destroy(&fdi); 815 } 816 817 /* 818 * Send a FUSE_SETATTR operation with no permissions checks. If cred is NULL, 819 * send the request with root credentials 820 */ 821 int fuse_internal_setattr(struct vnode *vp, struct vattr *vap, 822 struct thread *td, struct ucred *cred) 823 { 824 struct fuse_dispatcher fdi; 825 struct fuse_setattr_in *fsai; 826 struct mount *mp; 827 pid_t pid = td->td_proc->p_pid; 828 struct fuse_data *data; 829 int dataflags; 830 int err = 0; 831 enum vtype vtyp; 832 int sizechanged = -1; 833 uint64_t newsize = 0; 834 835 mp = vnode_mount(vp); 836 data = fuse_get_mpdata(mp); 837 dataflags = data->dataflags; 838 839 fdisp_init(&fdi, sizeof(*fsai)); 840 fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred); 841 if (!cred) { 842 fdi.finh->uid = 0; 843 fdi.finh->gid = 0; 844 } 845 fsai = fdi.indata; 846 fsai->valid = 0; 847 848 if (vap->va_uid != (uid_t)VNOVAL) { 849 fsai->uid = vap->va_uid; 850 fsai->valid |= FATTR_UID; 851 } 852 if (vap->va_gid != (gid_t)VNOVAL) { 853 fsai->gid = vap->va_gid; 854 fsai->valid |= FATTR_GID; 855 } 856 if (vap->va_size != VNOVAL) { 857 struct fuse_filehandle *fufh = NULL; 858 859 /*Truncate to a new value. */ 860 fsai->size = vap->va_size; 861 sizechanged = 1; 862 newsize = vap->va_size; 863 fsai->valid |= FATTR_SIZE; 864 865 fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid); 866 if (fufh) { 867 fsai->fh = fufh->fh_id; 868 fsai->valid |= FATTR_FH; 869 } 870 VTOFUD(vp)->flag &= ~FN_SIZECHANGE; 871 } 872 if (vap->va_atime.tv_sec != VNOVAL) { 873 fsai->atime = vap->va_atime.tv_sec; 874 fsai->atimensec = vap->va_atime.tv_nsec; 875 fsai->valid |= FATTR_ATIME; 876 if (vap->va_vaflags & VA_UTIMES_NULL) 877 fsai->valid |= FATTR_ATIME_NOW; 878 } 879 if (vap->va_mtime.tv_sec != VNOVAL) { 880 fsai->mtime = vap->va_mtime.tv_sec; 881 fsai->mtimensec = vap->va_mtime.tv_nsec; 882 fsai->valid |= FATTR_MTIME; 883 if (vap->va_vaflags & VA_UTIMES_NULL) 884 fsai->valid |= FATTR_MTIME_NOW; 885 } 886 if (vap->va_mode != (mode_t)VNOVAL) { 887 fsai->mode = vap->va_mode & ALLPERMS; 888 fsai->valid |= FATTR_MODE; 889 } 890 if (!fsai->valid) { 891 goto out; 892 } 893 894 if ((err = fdisp_wait_answ(&fdi))) 895 goto out; 896 vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode); 897 898 if (vnode_vtype(vp) != vtyp) { 899 if (vnode_vtype(vp) == VNON && vtyp != VNON) { 900 SDT_PROBE2(fusefs, , internal, trace, 1, "FUSE: Dang! " 901 "vnode_vtype is VNON and vtype isn't."); 902 } else { 903 /* 904 * STALE vnode, ditch 905 * 906 * The vnode has changed its type "behind our back". 907 * There's nothing really we can do, so let us just 908 * force an internal revocation and tell the caller to 909 * try again, if interested. 910 */ 911 fuse_internal_vnode_disappear(vp); 912 err = EAGAIN; 913 } 914 } 915 if (err == 0) { 916 struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ; 917 fuse_internal_cache_attrs(vp, cred, &fao->attr, fao->attr_valid, 918 fao->attr_valid_nsec, NULL); 919 } 920 921 out: 922 fdisp_destroy(&fdi); 923 return err; 924 } 925 926 #ifdef ZERO_PAD_INCOMPLETE_BUFS 927 static int 928 isbzero(void *buf, size_t len) 929 { 930 int i; 931 932 for (i = 0; i < len; i++) { 933 if (((char *)buf)[i]) 934 return (0); 935 } 936 937 return (1); 938 } 939 940 #endif 941