1 /* 2 * Copyright (c) 2007-2009 Google Inc. and Amit Singh 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * Copyright (C) 2005 Csaba Henk. 32 * All rights reserved. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions 36 * are met: 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 2. Redistributions in binary form must reproduce the above copyright 40 * notice, this list of conditions and the following disclaimer in the 41 * documentation and/or other materials provided with the distribution. 42 * 43 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56 #include <sys/cdefs.h> 57 __FBSDID("$FreeBSD$"); 58 59 #include <sys/types.h> 60 #include <sys/module.h> 61 #include <sys/systm.h> 62 #include <sys/errno.h> 63 #include <sys/param.h> 64 #include <sys/kernel.h> 65 #include <sys/conf.h> 66 #include <sys/uio.h> 67 #include <sys/malloc.h> 68 #include <sys/queue.h> 69 #include <sys/lock.h> 70 #include <sys/mutex.h> 71 #include <sys/sx.h> 72 #include <sys/proc.h> 73 #include <sys/mount.h> 74 #include <sys/vnode.h> 75 #include <sys/namei.h> 76 #include <sys/stat.h> 77 #include <sys/unistd.h> 78 #include <sys/filedesc.h> 79 #include <sys/file.h> 80 #include <sys/fcntl.h> 81 #include <sys/dirent.h> 82 #include <sys/bio.h> 83 #include <sys/buf.h> 84 #include <sys/sysctl.h> 85 #include <sys/priv.h> 86 87 #include "fuse.h" 88 #include "fuse_file.h" 89 #include "fuse_internal.h" 90 #include "fuse_ipc.h" 91 #include "fuse_node.h" 92 #include "fuse_file.h" 93 #include "fuse_param.h" 94 95 #define FUSE_DEBUG_MODULE INTERNAL 96 #include "fuse_debug.h" 97 98 #ifdef ZERO_PAD_INCOMPLETE_BUFS 99 static int isbzero(void *buf, size_t len); 100 101 #endif 102 103 /* access */ 104 105 int 106 fuse_internal_access(struct vnode *vp, 107 mode_t mode, 108 struct fuse_access_param *facp, 109 struct thread *td, 110 struct ucred *cred) 111 { 112 int err = 0; 113 uint32_t mask = 0; 114 int dataflags; 115 int vtype; 116 struct mount *mp; 117 struct fuse_dispatcher fdi; 118 struct fuse_access_in *fai; 119 struct fuse_data *data; 120 121 /* NOT YET DONE */ 122 /* 123 * If this vnop gives you trouble, just return 0 here for a lazy 124 * kludge. 125 */ 126 /* return 0;*/ 127 128 fuse_trace_printf_func(); 129 130 mp = vnode_mount(vp); 131 vtype = vnode_vtype(vp); 132 133 data = fuse_get_mpdata(mp); 134 dataflags = data->dataflags; 135 136 if ((mode & VWRITE) && vfs_isrdonly(mp)) { 137 return EACCES; 138 } 139 /* Unless explicitly permitted, deny everyone except the fs owner. */ 140 if (vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) { 141 if (!(dataflags & FSESS_DAEMON_CAN_SPY)) { 142 int denied = fuse_match_cred(data->daemoncred, 143 cred); 144 145 if (denied) { 146 return EPERM; 147 } 148 } 149 facp->facc_flags |= FACCESS_NOCHECKSPY; 150 } 151 if (!(facp->facc_flags & FACCESS_DO_ACCESS)) { 152 return 0; 153 } 154 if (((vtype == VREG) && (mode & VEXEC))) { 155 #ifdef NEED_MOUNT_ARGUMENT_FOR_THIS 156 /* Let the kernel handle this through open / close heuristics.*/ 157 return ENOTSUP; 158 #else 159 /* Let the kernel handle this. */ 160 return 0; 161 #endif 162 } 163 if (!fsess_isimpl(mp, FUSE_ACCESS)) { 164 /* Let the kernel handle this. */ 165 return 0; 166 } 167 if (dataflags & FSESS_DEFAULT_PERMISSIONS) { 168 /* Let the kernel handle this. */ 169 return 0; 170 } 171 if ((mode & VADMIN) != 0) { 172 err = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); 173 if (err) { 174 return err; 175 } 176 } 177 if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) { 178 mask |= W_OK; 179 } 180 if ((mode & VREAD) != 0) { 181 mask |= R_OK; 182 } 183 if ((mode & VEXEC) != 0) { 184 mask |= X_OK; 185 } 186 bzero(&fdi, sizeof(fdi)); 187 188 fdisp_init(&fdi, sizeof(*fai)); 189 fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred); 190 191 fai = fdi.indata; 192 fai->mask = F_OK; 193 fai->mask |= mask; 194 195 err = fdisp_wait_answ(&fdi); 196 fdisp_destroy(&fdi); 197 198 if (err == ENOSYS) { 199 fsess_set_notimpl(mp, FUSE_ACCESS); 200 err = 0; 201 } 202 return err; 203 } 204 205 /* fsync */ 206 207 int 208 fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio) 209 { 210 fuse_trace_printf_func(); 211 212 if (tick->tk_aw_ohead.error == ENOSYS) { 213 fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick)); 214 } 215 return 0; 216 } 217 218 int 219 fuse_internal_fsync(struct vnode *vp, 220 struct thread *td, 221 struct ucred *cred, 222 struct fuse_filehandle *fufh) 223 { 224 int op = FUSE_FSYNC; 225 struct fuse_fsync_in *ffsi; 226 struct fuse_dispatcher fdi; 227 228 fuse_trace_printf_func(); 229 230 if (vnode_isdir(vp)) { 231 op = FUSE_FSYNCDIR; 232 } 233 fdisp_init(&fdi, sizeof(*ffsi)); 234 fdisp_make_vp(&fdi, op, vp, td, cred); 235 ffsi = fdi.indata; 236 ffsi->fh = fufh->fh_id; 237 238 ffsi->fsync_flags = 1; /* datasync */ 239 240 fuse_insert_callback(fdi.tick, fuse_internal_fsync_callback); 241 fuse_insert_message(fdi.tick); 242 243 fdisp_destroy(&fdi); 244 245 return 0; 246 247 } 248 249 /* readdir */ 250 251 int 252 fuse_internal_readdir(struct vnode *vp, 253 struct uio *uio, 254 struct fuse_filehandle *fufh, 255 struct fuse_iov *cookediov) 256 { 257 int err = 0; 258 struct fuse_dispatcher fdi; 259 struct fuse_read_in *fri; 260 261 if (uio_resid(uio) == 0) { 262 return 0; 263 } 264 fdisp_init(&fdi, 0); 265 266 /* 267 * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p 268 * I/O). 269 */ 270 271 while (uio_resid(uio) > 0) { 272 273 fdi.iosize = sizeof(*fri); 274 fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); 275 276 fri = fdi.indata; 277 fri->fh = fufh->fh_id; 278 fri->offset = uio_offset(uio); 279 fri->size = min(uio_resid(uio), FUSE_DEFAULT_IOSIZE); 280 /* mp->max_read */ 281 282 if ((err = fdisp_wait_answ(&fdi))) { 283 break; 284 } 285 if ((err = fuse_internal_readdir_processdata(uio, fri->size, fdi.answ, 286 fdi.iosize, cookediov))) { 287 break; 288 } 289 } 290 291 fdisp_destroy(&fdi); 292 return ((err == -1) ? 0 : err); 293 } 294 295 int 296 fuse_internal_readdir_processdata(struct uio *uio, 297 size_t reqsize, 298 void *buf, 299 size_t bufsize, 300 void *param) 301 { 302 int err = 0; 303 int cou = 0; 304 int bytesavail; 305 size_t freclen; 306 307 struct dirent *de; 308 struct fuse_dirent *fudge; 309 struct fuse_iov *cookediov = param; 310 311 if (bufsize < FUSE_NAME_OFFSET) { 312 return -1; 313 } 314 for (;;) { 315 316 if (bufsize < FUSE_NAME_OFFSET) { 317 err = -1; 318 break; 319 } 320 fudge = (struct fuse_dirent *)buf; 321 freclen = FUSE_DIRENT_SIZE(fudge); 322 323 cou++; 324 325 if (bufsize < freclen) { 326 err = ((cou == 1) ? -1 : 0); 327 break; 328 } 329 #ifdef ZERO_PAD_INCOMPLETE_BUFS 330 if (isbzero(buf, FUSE_NAME_OFFSET)) { 331 err = -1; 332 break; 333 } 334 #endif 335 336 if (!fudge->namelen || fudge->namelen > MAXNAMLEN) { 337 err = EINVAL; 338 break; 339 } 340 bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *) 341 &fudge->namelen); 342 343 if (bytesavail > uio_resid(uio)) { 344 err = -1; 345 break; 346 } 347 fiov_refresh(cookediov); 348 fiov_adjust(cookediov, bytesavail); 349 350 de = (struct dirent *)cookediov->base; 351 de->d_fileno = fudge->ino; /* XXX: truncation */ 352 de->d_reclen = bytesavail; 353 de->d_type = fudge->type; 354 de->d_namlen = fudge->namelen; 355 memcpy((char *)cookediov->base + sizeof(struct dirent) - 356 MAXNAMLEN - 1, 357 (char *)buf + FUSE_NAME_OFFSET, fudge->namelen); 358 ((char *)cookediov->base)[bytesavail] = '\0'; 359 360 err = uiomove(cookediov->base, cookediov->len, uio); 361 if (err) { 362 break; 363 } 364 buf = (char *)buf + freclen; 365 bufsize -= freclen; 366 uio_setoffset(uio, fudge->off); 367 } 368 369 return err; 370 } 371 372 /* remove */ 373 374 #ifdef XXXIP 375 static int 376 fuse_internal_remove_callback(struct vnode *vp, void *cargs) 377 { 378 struct vattr *vap; 379 uint64_t target_nlink; 380 381 vap = VTOVA(vp); 382 383 target_nlink = *(uint64_t *)cargs; 384 385 /* somewhat lame "heuristics", but you got better ideas? */ 386 if ((vap->va_nlink == target_nlink) && vnode_isreg(vp)) { 387 fuse_invalidate_attr(vp); 388 } 389 return 0; 390 } 391 392 #endif 393 394 #define INVALIDATE_CACHED_VATTRS_UPON_UNLINK 1 395 int 396 fuse_internal_remove(struct vnode *dvp, 397 struct vnode *vp, 398 struct componentname *cnp, 399 enum fuse_opcode op) 400 { 401 struct fuse_dispatcher fdi; 402 403 struct vattr *vap = VTOVA(vp); 404 405 #if INVALIDATE_CACHED_VATTRS_UPON_UNLINK 406 int need_invalidate = 0; 407 uint64_t target_nlink = 0; 408 409 #endif 410 int err = 0; 411 412 debug_printf("dvp=%p, cnp=%p, op=%d\n", vp, cnp, op); 413 414 fdisp_init(&fdi, cnp->cn_namelen + 1); 415 fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred); 416 417 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 418 ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 419 420 #if INVALIDATE_CACHED_VATTRS_UPON_UNLINK 421 if (vap->va_nlink > 1) { 422 need_invalidate = 1; 423 target_nlink = vap->va_nlink; 424 } 425 #endif 426 427 err = fdisp_wait_answ(&fdi); 428 fdisp_destroy(&fdi); 429 430 fuse_invalidate_attr(dvp); 431 fuse_invalidate_attr(vp); 432 433 #ifdef XXXIP 434 /* 435 * XXX: INVALIDATE_CACHED_VATTRS_UPON_UNLINK 436 * 437 * Consider the case where vap->va_nlink > 1 for the entity being 438 * removed. In our world, other in-memory vnodes that share a link 439 * count each with this one may not know right way that this one just 440 * got deleted. We should let them know, say, through a vnode_iterate() 441 * here and a callback that does fuse_invalidate_attr(vp) on each 442 * relevant vnode. 443 */ 444 if (need_invalidate && !err) { 445 vnode_iterate(vnode_mount(vp), 0, fuse_internal_remove_callback, 446 (void *)&target_nlink); 447 } 448 #endif 449 450 return err; 451 } 452 453 /* rename */ 454 455 int 456 fuse_internal_rename(struct vnode *fdvp, 457 struct componentname *fcnp, 458 struct vnode *tdvp, 459 struct componentname *tcnp) 460 { 461 struct fuse_dispatcher fdi; 462 struct fuse_rename_in *fri; 463 int err = 0; 464 465 fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2); 466 fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred); 467 468 fri = fdi.indata; 469 fri->newdir = VTOI(tdvp); 470 memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr, 471 fcnp->cn_namelen); 472 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0'; 473 memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1, 474 tcnp->cn_nameptr, tcnp->cn_namelen); 475 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen + 476 tcnp->cn_namelen + 1] = '\0'; 477 478 err = fdisp_wait_answ(&fdi); 479 fdisp_destroy(&fdi); 480 481 fuse_invalidate_attr(fdvp); 482 if (tdvp != fdvp) { 483 fuse_invalidate_attr(tdvp); 484 } 485 return err; 486 } 487 488 /* strategy */ 489 490 /* entity creation */ 491 492 void 493 fuse_internal_newentry_makerequest(struct mount *mp, 494 uint64_t dnid, 495 struct componentname *cnp, 496 enum fuse_opcode op, 497 void *buf, 498 size_t bufsize, 499 struct fuse_dispatcher *fdip) 500 { 501 debug_printf("fdip=%p\n", fdip); 502 503 fdip->iosize = bufsize + cnp->cn_namelen + 1; 504 505 fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred); 506 memcpy(fdip->indata, buf, bufsize); 507 memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen); 508 ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0'; 509 } 510 511 int 512 fuse_internal_newentry_core(struct vnode *dvp, 513 struct vnode **vpp, 514 struct componentname *cnp, 515 enum vtype vtyp, 516 struct fuse_dispatcher *fdip) 517 { 518 int err = 0; 519 struct fuse_entry_out *feo; 520 struct mount *mp = vnode_mount(dvp); 521 522 if ((err = fdisp_wait_answ(fdip))) { 523 return err; 524 } 525 feo = fdip->answ; 526 527 if ((err = fuse_internal_checkentry(feo, vtyp))) { 528 return err; 529 } 530 err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, vtyp); 531 if (err) { 532 fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred, 533 feo->nodeid, 1); 534 return err; 535 } 536 cache_attrs(*vpp, feo); 537 538 return err; 539 } 540 541 int 542 fuse_internal_newentry(struct vnode *dvp, 543 struct vnode **vpp, 544 struct componentname *cnp, 545 enum fuse_opcode op, 546 void *buf, 547 size_t bufsize, 548 enum vtype vtype) 549 { 550 int err; 551 struct fuse_dispatcher fdi; 552 struct mount *mp = vnode_mount(dvp); 553 554 fdisp_init(&fdi, 0); 555 fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf, 556 bufsize, &fdi); 557 err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi); 558 fdisp_destroy(&fdi); 559 fuse_invalidate_attr(dvp); 560 561 return err; 562 } 563 564 /* entity destruction */ 565 566 int 567 fuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio) 568 { 569 fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL, 570 ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1); 571 572 return 0; 573 } 574 575 void 576 fuse_internal_forget_send(struct mount *mp, 577 struct thread *td, 578 struct ucred *cred, 579 uint64_t nodeid, 580 uint64_t nlookup) 581 { 582 583 struct fuse_dispatcher fdi; 584 struct fuse_forget_in *ffi; 585 586 debug_printf("mp=%p, nodeid=%ju, nlookup=%ju\n", 587 mp, (uintmax_t)nodeid, (uintmax_t)nlookup); 588 589 /* 590 * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu", 591 * (long long unsigned) nodeid)); 592 */ 593 594 fdisp_init(&fdi, sizeof(*ffi)); 595 fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred); 596 597 ffi = fdi.indata; 598 ffi->nlookup = nlookup; 599 600 fuse_insert_message(fdi.tick); 601 fdisp_destroy(&fdi); 602 } 603 604 void 605 fuse_internal_vnode_disappear(struct vnode *vp) 606 { 607 struct fuse_vnode_data *fvdat = VTOFUD(vp); 608 609 ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear"); 610 fvdat->flag |= FN_REVOKED; 611 cache_purge(vp); 612 } 613 614 /* fuse start/stop */ 615 616 int 617 fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio) 618 { 619 int err = 0; 620 struct fuse_data *data = tick->tk_data; 621 struct fuse_init_out *fiio; 622 623 if ((err = tick->tk_aw_ohead.error)) { 624 goto out; 625 } 626 if ((err = fticket_pull(tick, uio))) { 627 goto out; 628 } 629 fiio = fticket_resp(tick)->base; 630 631 /* XXX: Do we want to check anything further besides this? */ 632 if (fiio->major < 7) { 633 debug_printf("userpace version too low\n"); 634 err = EPROTONOSUPPORT; 635 goto out; 636 } 637 data->fuse_libabi_major = fiio->major; 638 data->fuse_libabi_minor = fiio->minor; 639 640 if (fuse_libabi_geq(data, 7, 5)) { 641 if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) { 642 data->max_write = fiio->max_write; 643 } else { 644 err = EINVAL; 645 } 646 } else { 647 /* Old fix values */ 648 data->max_write = 4096; 649 } 650 651 out: 652 if (err) { 653 fdata_set_dead(data); 654 } 655 FUSE_LOCK(); 656 data->dataflags |= FSESS_INITED; 657 wakeup(&data->ticketer); 658 FUSE_UNLOCK(); 659 660 return 0; 661 } 662 663 void 664 fuse_internal_send_init(struct fuse_data *data, struct thread *td) 665 { 666 struct fuse_init_in *fiii; 667 struct fuse_dispatcher fdi; 668 669 fdisp_init(&fdi, sizeof(*fiii)); 670 fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL); 671 fiii = fdi.indata; 672 fiii->major = FUSE_KERNEL_VERSION; 673 fiii->minor = FUSE_KERNEL_MINOR_VERSION; 674 fiii->max_readahead = FUSE_DEFAULT_IOSIZE * 16; 675 fiii->flags = 0; 676 677 fuse_insert_callback(fdi.tick, fuse_internal_init_callback); 678 fuse_insert_message(fdi.tick); 679 fdisp_destroy(&fdi); 680 } 681 682 #ifdef ZERO_PAD_INCOMPLETE_BUFS 683 static int 684 isbzero(void *buf, size_t len) 685 { 686 int i; 687 688 for (i = 0; i < len; i++) { 689 if (((char *)buf)[i]) 690 return (0); 691 } 692 693 return (1); 694 } 695 696 #endif 697