1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 #include <sys/types.h> 17 #include <sys/param.h> 18 #include <sys/systm.h> 19 #include <sys/t_lock.h> 20 #include <sys/errno.h> 21 #include <sys/cred.h> 22 #include <sys/user.h> 23 #include <sys/uio.h> 24 #include <sys/file.h> 25 #include <sys/pathname.h> 26 #include <sys/vfs.h> 27 #include <sys/vnode.h> 28 #include <sys/stat.h> 29 #include <sys/mode.h> 30 #include <sys/kmem.h> 31 #include <sys/cmn_err.h> 32 #include <sys/debug.h> 33 #include <sys/atomic.h> 34 #include <sys/acl.h> 35 #include <sys/filio.h> 36 #include <sys/flock.h> 37 #include <sys/nbmlock.h> 38 #include <sys/fcntl.h> 39 #include <sys/poll.h> 40 #include <sys/time.h> 41 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <unistd.h> 45 46 #include "vncache.h" 47 48 #define O_RWMASK (O_WRONLY | O_RDWR) /* == 3 */ 49 50 int fop_shrlock_enable = 0; 51 52 int stat_to_vattr(const struct stat *, vattr_t *); 53 int fop__getxvattr(vnode_t *, xvattr_t *); 54 int fop__setxvattr(vnode_t *, xvattr_t *); 55 56 static void fake_inactive_xattrdir(vnode_t *); 57 58 /* ARGSUSED */ 59 int 60 fop_open( 61 vnode_t **vpp, 62 int mode, 63 cred_t *cr, 64 caller_context_t *ct) 65 { 66 67 if ((*vpp)->v_type == VREG) { 68 if (mode & FREAD) 69 atomic_add_32(&((*vpp)->v_rdcnt), 1); 70 if (mode & FWRITE) 71 atomic_add_32(&((*vpp)->v_wrcnt), 1); 72 } 73 74 /* call to ->vop_open was here */ 75 76 return (0); 77 } 78 79 /* ARGSUSED */ 80 int 81 fop_close( 82 vnode_t *vp, 83 int flag, 84 int count, 85 offset_t offset, 86 cred_t *cr, 87 caller_context_t *ct) 88 { 89 90 /* call to ->vop_close was here */ 91 92 /* 93 * Check passed in count to handle possible dups. Vnode counts are only 94 * kept on regular files 95 */ 96 if ((vp->v_type == VREG) && (count == 1)) { 97 if (flag & FREAD) { 98 ASSERT(vp->v_rdcnt > 0); 99 atomic_add_32(&(vp->v_rdcnt), -1); 100 } 101 if (flag & FWRITE) { 102 ASSERT(vp->v_wrcnt > 0); 103 atomic_add_32(&(vp->v_wrcnt), -1); 104 } 105 } 106 return (0); 107 } 108 109 /* ARGSUSED */ 110 int 111 fop_read( 112 vnode_t *vp, 113 uio_t *uio, 114 int ioflag, 115 cred_t *cr, 116 caller_context_t *ct) 117 { 118 struct stat st; 119 struct iovec *iov; 120 ssize_t resid; 121 size_t cnt; 122 int n; 123 124 /* 125 * If that caller asks for read beyond end of file, 126 * that causes the pread call to block. (Ugh!) 127 * Get the file size and return what we can. 128 */ 129 (void) fstat(vp->v_fd, &st); 130 resid = uio->uio_resid; 131 if ((uio->uio_loffset + resid) > st.st_size) 132 resid = st.st_size - uio->uio_loffset; 133 134 while (resid > 0) { 135 136 ASSERT(uio->uio_iovcnt > 0); 137 iov = uio->uio_iov; 138 139 if (iov->iov_len == 0) { 140 uio->uio_iov++; 141 uio->uio_iovcnt--; 142 continue; 143 } 144 cnt = iov->iov_len; 145 if (cnt > resid) 146 cnt = resid; 147 148 n = pread(vp->v_fd, iov->iov_base, cnt, uio->uio_loffset); 149 if (n < 0) 150 return (errno); 151 152 iov->iov_base += n; 153 iov->iov_len -= n; 154 155 uio->uio_resid -= n; 156 uio->uio_loffset += n; 157 158 resid -= n; 159 } 160 161 return (0); 162 } 163 164 /* ARGSUSED */ 165 int 166 fop_write( 167 vnode_t *vp, 168 uio_t *uio, 169 int ioflag, 170 cred_t *cr, 171 caller_context_t *ct) 172 { 173 struct iovec *iov; 174 size_t cnt; 175 int n; 176 177 while (uio->uio_resid > 0) { 178 179 ASSERT(uio->uio_iovcnt > 0); 180 iov = uio->uio_iov; 181 182 if (iov->iov_len == 0) { 183 uio->uio_iov++; 184 uio->uio_iovcnt--; 185 continue; 186 } 187 cnt = iov->iov_len; 188 if (cnt > uio->uio_resid) 189 cnt = uio->uio_resid; 190 191 n = pwrite(vp->v_fd, iov->iov_base, iov->iov_len, 192 uio->uio_loffset); 193 if (n < 0) 194 return (errno); 195 196 iov->iov_base += n; 197 iov->iov_len -= n; 198 199 uio->uio_resid -= n; 200 uio->uio_loffset += n; 201 } 202 203 if (ioflag == FSYNC) { 204 (void) fsync(vp->v_fd); 205 } 206 207 return (0); 208 } 209 210 /* ARGSUSED */ 211 int 212 fop_ioctl( 213 vnode_t *vp, 214 int cmd, 215 intptr_t arg, 216 int flag, 217 cred_t *cr, 218 int *rvalp, 219 caller_context_t *ct) 220 { 221 return (ENOSYS); 222 } 223 224 /* ARGSUSED */ 225 int 226 fop_setfl( 227 vnode_t *vp, 228 int oflags, 229 int nflags, 230 cred_t *cr, 231 caller_context_t *ct) 232 { 233 /* allow any flags? See fs_setfl */ 234 return (0); 235 } 236 237 /* ARGSUSED */ 238 int 239 fop_getattr( 240 vnode_t *vp, 241 vattr_t *vap, 242 int flags, 243 cred_t *cr, 244 caller_context_t *ct) 245 { 246 int error; 247 struct stat st; 248 249 if (fstat(vp->v_fd, &st) == -1) 250 return (errno); 251 error = stat_to_vattr(&st, vap); 252 253 if (vap->va_mask & AT_XVATTR) 254 (void) fop__getxvattr(vp, (xvattr_t *)vap); 255 256 return (error); 257 } 258 259 /* ARGSUSED */ 260 int 261 fop_setattr( 262 vnode_t *vp, 263 vattr_t *vap, 264 int flags, 265 cred_t *cr, 266 caller_context_t *ct) 267 { 268 timespec_t times[2]; 269 270 if (vap->va_mask & AT_SIZE) { 271 if (ftruncate(vp->v_fd, vap->va_size) == -1) 272 return (errno); 273 } 274 275 /* AT_MODE or anything else? */ 276 277 if (vap->va_mask & AT_XVATTR) 278 (void) fop__setxvattr(vp, (xvattr_t *)vap); 279 280 if (vap->va_mask & (AT_ATIME | AT_MTIME)) { 281 if (vap->va_mask & AT_ATIME) { 282 times[0] = vap->va_atime; 283 } else { 284 times[0].tv_sec = 0; 285 times[0].tv_nsec = UTIME_OMIT; 286 } 287 if (vap->va_mask & AT_MTIME) { 288 times[1] = vap->va_mtime; 289 } else { 290 times[1].tv_sec = 0; 291 times[1].tv_nsec = UTIME_OMIT; 292 } 293 294 (void) futimens(vp->v_fd, times); 295 } 296 297 return (0); 298 } 299 300 /* ARGSUSED */ 301 int 302 fop_access( 303 vnode_t *vp, 304 int mode, 305 int flags, 306 cred_t *cr, 307 caller_context_t *ct) 308 { 309 return (0); 310 } 311 312 /* 313 * Conceptually like xattr_dir_lookup() 314 */ 315 static int 316 fake_lookup_xattrdir( 317 vnode_t *dvp, 318 vnode_t **vpp) 319 { 320 int len, fd; 321 int omode = O_RDWR | O_NOFOLLOW; 322 vnode_t *vp; 323 324 *vpp = NULL; 325 326 if (dvp->v_type != VDIR && dvp->v_type != VREG) 327 return (EINVAL); 328 329 /* 330 * If we're already in sysattr space, don't allow creation 331 * of another level of sysattrs. 332 */ 333 if (dvp->v_flag & V_SYSATTR) 334 return (EINVAL); 335 336 mutex_enter(&dvp->v_lock); 337 if (dvp->v_xattrdir != NULL) { 338 *vpp = dvp->v_xattrdir; 339 VN_HOLD(*vpp); 340 mutex_exit(&dvp->v_lock); 341 return (0); 342 } 343 mutex_exit(&dvp->v_lock); 344 345 omode = O_RDONLY|O_XATTR; 346 fd = openat(dvp->v_fd, ".", omode); 347 if (fd < 0) 348 return (errno); 349 350 vp = vn_alloc(KM_SLEEP); 351 vp->v_fd = fd; 352 vp->v_flag = V_XATTRDIR|V_SYSATTR; 353 vp->v_type = VDIR; 354 vp->v_vfsp = dvp->v_vfsp; 355 356 /* Set v_path to parent path + "/@" (like NFS) */ 357 len = strlen(dvp->v_path) + 3; 358 vp->v_path = kmem_alloc(len, KM_SLEEP); 359 (void) snprintf(vp->v_path, len, "%s/@", dvp->v_path); 360 361 /* 362 * Keep a pointer to the parent and a hold on it. 363 * Both are cleaned up in fake_inactive_xattrdir 364 */ 365 vp->v_data = dvp; 366 vn_hold(dvp); 367 368 mutex_enter(&dvp->v_lock); 369 if (dvp->v_xattrdir == NULL) { 370 *vpp = dvp->v_xattrdir = vp; 371 mutex_exit(&dvp->v_lock); 372 } else { 373 *vpp = dvp->v_xattrdir; 374 mutex_exit(&dvp->v_lock); 375 fake_inactive_xattrdir(vp); 376 } 377 378 return (0); 379 } 380 381 /* ARGSUSED */ 382 int 383 fop_lookup( 384 vnode_t *dvp, 385 char *name, 386 vnode_t **vpp, 387 pathname_t *pnp, 388 int flags, 389 vnode_t *rdir, 390 cred_t *cr, 391 caller_context_t *ct, 392 int *deflags, /* Returned per-dirent flags */ 393 pathname_t *ppnp) /* Returned case-preserved name in directory */ 394 { 395 int fd; 396 int omode = O_RDWR | O_NOFOLLOW; 397 vnode_t *vp; 398 struct stat st; 399 400 if (flags & LOOKUP_XATTR) 401 return (fake_lookup_xattrdir(dvp, vpp)); 402 403 /* 404 * If lookup is for "", just return dvp. 405 */ 406 if (name[0] == '\0') { 407 vn_hold(dvp); 408 *vpp = dvp; 409 return (0); 410 } 411 412 if (fstatat(dvp->v_fd, name, &st, AT_SYMLINK_NOFOLLOW) == -1) 413 return (errno); 414 415 vp = vncache_lookup(&st); 416 if (vp != NULL) { 417 /* lookup gave us a hold */ 418 *vpp = vp; 419 return (0); 420 } 421 422 if (S_ISDIR(st.st_mode)) 423 omode = O_RDONLY | O_NOFOLLOW; 424 425 again: 426 fd = openat(dvp->v_fd, name, omode, 0); 427 if (fd < 0) { 428 if ((omode & O_RWMASK) == O_RDWR) { 429 omode &= ~O_RWMASK; 430 omode |= O_RDONLY; 431 goto again; 432 } 433 return (errno); 434 } 435 436 if (fstat(fd, &st) == -1) { 437 (void) close(fd); 438 return (errno); 439 } 440 441 vp = vncache_enter(&st, dvp, name, fd); 442 443 *vpp = vp; 444 return (0); 445 } 446 447 /* ARGSUSED */ 448 int 449 fop_create( 450 vnode_t *dvp, 451 char *name, 452 vattr_t *vap, 453 vcexcl_t excl, 454 int mode, 455 vnode_t **vpp, 456 cred_t *cr, 457 int flags, 458 caller_context_t *ct, 459 vsecattr_t *vsecp) /* ACL to set during create */ 460 { 461 struct stat st; 462 vnode_t *vp; 463 int err, fd, omode; 464 465 /* 466 * If creating "", just return dvp. 467 */ 468 if (name[0] == '\0') { 469 vn_hold(dvp); 470 *vpp = dvp; 471 return (0); 472 } 473 474 err = fstatat(dvp->v_fd, name, &st, AT_SYMLINK_NOFOLLOW); 475 if (err != 0) 476 err = errno; 477 478 vp = NULL; 479 if (err == 0) { 480 /* The file already exists. */ 481 if (excl == EXCL) 482 return (EEXIST); 483 484 vp = vncache_lookup(&st); 485 /* vp gained a hold */ 486 } 487 488 if (vp == NULL) { 489 /* 490 * Open it. (may or may not exist) 491 */ 492 omode = O_RDWR | O_CREAT | O_NOFOLLOW; 493 if (excl == EXCL) 494 omode |= O_EXCL; 495 open_again: 496 fd = openat(dvp->v_fd, name, omode, mode); 497 if (fd < 0) { 498 if ((omode & O_RWMASK) == O_RDWR) { 499 omode &= ~O_RWMASK; 500 omode |= O_RDONLY; 501 goto open_again; 502 } 503 return (errno); 504 } 505 (void) fstat(fd, &st); 506 507 vp = vncache_enter(&st, dvp, name, fd); 508 /* vp has its initial hold */ 509 } 510 511 /* Should have the vp now. */ 512 if (vp == NULL) 513 return (EFAULT); 514 515 if (vp->v_type == VDIR && vap->va_type != VDIR) { 516 vn_rele(vp); 517 return (EISDIR); 518 } 519 if (vp->v_type != VDIR && vap->va_type == VDIR) { 520 vn_rele(vp); 521 return (ENOTDIR); 522 } 523 524 /* 525 * Might need to set attributes. 526 */ 527 (void) fop_setattr(vp, vap, 0, cr, ct); 528 529 *vpp = vp; 530 return (0); 531 } 532 533 /* ARGSUSED */ 534 int 535 fop_remove( 536 vnode_t *dvp, 537 char *name, 538 cred_t *cr, 539 caller_context_t *ct, 540 int flags) 541 { 542 543 if (unlinkat(dvp->v_fd, name, 0)) 544 return (errno); 545 546 return (0); 547 } 548 549 /* ARGSUSED */ 550 int 551 fop_link( 552 vnode_t *to_dvp, 553 vnode_t *fr_vp, 554 char *to_name, 555 cred_t *cr, 556 caller_context_t *ct, 557 int flags) 558 { 559 int err; 560 561 /* 562 * Would prefer to specify "from" as the combination: 563 * (fr_vp->v_fd, NULL) but linkat does not permit it. 564 */ 565 err = linkat(AT_FDCWD, fr_vp->v_path, to_dvp->v_fd, to_name, 566 AT_SYMLINK_FOLLOW); 567 if (err == -1) 568 err = errno; 569 570 return (err); 571 } 572 573 /* ARGSUSED */ 574 int 575 fop_rename( 576 vnode_t *from_dvp, 577 char *from_name, 578 vnode_t *to_dvp, 579 char *to_name, 580 cred_t *cr, 581 caller_context_t *ct, 582 int flags) 583 { 584 struct stat st; 585 vnode_t *vp; 586 int err; 587 588 if (fstatat(from_dvp->v_fd, from_name, &st, 589 AT_SYMLINK_NOFOLLOW) == -1) 590 return (errno); 591 592 vp = vncache_lookup(&st); 593 if (vp == NULL) 594 return (ENOENT); 595 596 err = renameat(from_dvp->v_fd, from_name, to_dvp->v_fd, to_name); 597 if (err == -1) 598 err = errno; 599 else 600 vncache_renamed(vp, to_dvp, to_name); 601 602 vn_rele(vp); 603 604 return (err); 605 } 606 607 /* ARGSUSED */ 608 int 609 fop_mkdir( 610 vnode_t *dvp, 611 char *name, 612 vattr_t *vap, 613 vnode_t **vpp, 614 cred_t *cr, 615 caller_context_t *ct, 616 int flags, 617 vsecattr_t *vsecp) /* ACL to set during create */ 618 { 619 struct stat st; 620 int err, fd; 621 622 mode_t mode = vap->va_mode & 0777; 623 624 if (mkdirat(dvp->v_fd, name, mode) == -1) 625 return (errno); 626 627 if ((fd = openat(dvp->v_fd, name, O_RDONLY)) == -1) 628 return (errno); 629 if (fstat(fd, &st) == -1) { 630 err = errno; 631 (void) close(fd); 632 return (err); 633 } 634 635 *vpp = vncache_enter(&st, dvp, name, fd); 636 637 /* 638 * Might need to set attributes. 639 */ 640 (void) fop_setattr(*vpp, vap, 0, cr, ct); 641 642 return (0); 643 } 644 645 /* ARGSUSED */ 646 int 647 fop_rmdir( 648 vnode_t *dvp, 649 char *name, 650 vnode_t *cdir, 651 cred_t *cr, 652 caller_context_t *ct, 653 int flags) 654 { 655 656 if (unlinkat(dvp->v_fd, name, AT_REMOVEDIR) == -1) 657 return (errno); 658 659 return (0); 660 } 661 662 /* ARGSUSED */ 663 int 664 fop_readdir( 665 vnode_t *vp, 666 uio_t *uiop, 667 cred_t *cr, 668 int *eofp, 669 caller_context_t *ct, 670 int flags) 671 { 672 struct iovec *iov; 673 int cnt; 674 int error = 0; 675 int fd = vp->v_fd; 676 677 if (eofp) { 678 *eofp = 0; 679 } 680 681 error = lseek(fd, uiop->uio_loffset, SEEK_SET); 682 if (error == -1) 683 return (errno); 684 685 ASSERT(uiop->uio_iovcnt > 0); 686 iov = uiop->uio_iov; 687 if (iov->iov_len < sizeof (struct dirent)) 688 return (EINVAL); 689 690 /* LINTED E_BAD_PTR_CAST_ALIGN */ 691 cnt = getdents(fd, (struct dirent *)(uiop->uio_iov->iov_base), 692 uiop->uio_resid); 693 if (cnt == -1) 694 return (errno); 695 if (cnt == 0) { 696 if (eofp) { 697 *eofp = 1; 698 } 699 return (ENOENT); 700 } 701 702 iov->iov_base += cnt; 703 iov->iov_len -= cnt; 704 uiop->uio_resid -= cnt; 705 uiop->uio_loffset = lseek(fd, 0LL, SEEK_CUR); 706 707 return (0); 708 } 709 710 /* ARGSUSED */ 711 int 712 fop_symlink( 713 vnode_t *dvp, 714 char *linkname, 715 vattr_t *vap, 716 char *target, 717 cred_t *cr, 718 caller_context_t *ct, 719 int flags) 720 { 721 return (ENOSYS); 722 } 723 724 /* ARGSUSED */ 725 int 726 fop_readlink( 727 vnode_t *vp, 728 uio_t *uiop, 729 cred_t *cr, 730 caller_context_t *ct) 731 { 732 return (ENOSYS); 733 } 734 735 /* ARGSUSED */ 736 int 737 fop_fsync( 738 vnode_t *vp, 739 int syncflag, 740 cred_t *cr, 741 caller_context_t *ct) 742 { 743 744 if (fsync(vp->v_fd) == -1) 745 return (errno); 746 747 return (0); 748 } 749 750 /* ARGSUSED */ 751 void 752 fop_inactive( 753 vnode_t *vp, 754 cred_t *cr, 755 caller_context_t *ct) 756 { 757 if (vp->v_flag & V_XATTRDIR) { 758 fake_inactive_xattrdir(vp); 759 } else { 760 vncache_inactive(vp); 761 } 762 } 763 764 /* 765 * The special xattr directories are not in the vncache AVL, but 766 * hang off the parent's v_xattrdir field. When vn_rele finds 767 * an xattr dir at v_count == 1 it calls here, but until we 768 * take locks on both the parent and the xattrdir, we don't 769 * know if we're really at the last reference. So in here we 770 * take both locks, re-check the count, and either bail out 771 * or proceed with "inactive" vnode cleanup. Part of that 772 * cleanup includes releasing the hold on the parent and 773 * clearing the parent's v_xattrdir field, which were 774 * setup in fake_lookup_xattrdir() 775 */ 776 static void 777 fake_inactive_xattrdir(vnode_t *vp) 778 { 779 vnode_t *dvp = vp->v_data; /* parent */ 780 mutex_enter(&dvp->v_lock); 781 mutex_enter(&vp->v_lock); 782 if (vp->v_count > 1) { 783 /* new ref. via v_xattrdir */ 784 mutex_exit(&vp->v_lock); 785 mutex_exit(&dvp->v_lock); 786 return; 787 } 788 ASSERT(dvp->v_xattrdir == vp); 789 dvp->v_xattrdir = NULL; 790 mutex_exit(&vp->v_lock); 791 mutex_exit(&dvp->v_lock); 792 vn_rele(dvp); 793 vn_free(vp); 794 } 795 796 /* ARGSUSED */ 797 int 798 fop_fid( 799 vnode_t *vp, 800 fid_t *fidp, 801 caller_context_t *ct) 802 { 803 return (ENOSYS); 804 } 805 806 /* ARGSUSED */ 807 int 808 fop_rwlock( 809 vnode_t *vp, 810 int write_lock, 811 caller_context_t *ct) 812 { 813 /* See: fs_rwlock */ 814 return (-1); 815 } 816 817 /* ARGSUSED */ 818 void 819 fop_rwunlock( 820 vnode_t *vp, 821 int write_lock, 822 caller_context_t *ct) 823 { 824 /* See: fs_rwunlock */ 825 } 826 827 /* ARGSUSED */ 828 int 829 fop_seek( 830 vnode_t *vp, 831 offset_t ooff, 832 offset_t *noffp, 833 caller_context_t *ct) 834 { 835 return (ENOSYS); 836 } 837 838 /* ARGSUSED */ 839 int 840 fop_cmp( 841 vnode_t *vp1, 842 vnode_t *vp2, 843 caller_context_t *ct) 844 { 845 /* See fs_cmp */ 846 return (vncache_cmp(vp1, vp2)); 847 } 848 849 /* ARGSUSED */ 850 int 851 fop_frlock( 852 vnode_t *vp, 853 int cmd, 854 flock64_t *bfp, 855 int flag, 856 offset_t offset, 857 struct flk_callback *flk_cbp, 858 cred_t *cr, 859 caller_context_t *ct) 860 { 861 #if defined(_LP64) 862 offset_t maxoffset = INT64_MAX; 863 #elif defined(_ILP32) 864 /* 865 * Sadly, the fcntl API enforces 32-bit offsets, 866 * even though we have _FILE_OFFSET_BITS=64 867 */ 868 offset_t maxoffset = INT32_MAX; 869 #else 870 #error "unsupported env." 871 #endif 872 873 /* See fs_frlock */ 874 875 switch (cmd) { 876 case F_GETLK: 877 case F_SETLK_NBMAND: 878 case F_SETLK: 879 case F_SETLKW: 880 break; 881 default: 882 return (EINVAL); 883 } 884 885 /* We only get SEEK_SET ranges here. */ 886 if (bfp->l_whence != 0) 887 return (EINVAL); 888 889 /* 890 * One limitation of using fcntl(2) F_SETLK etc is that 891 * the real kernel limits the offsets we can use. 892 * (Maybe the fcntl API should loosen that up?) 893 * See syscall/fcntl.c:flock_check() 894 * 895 * Here in libfksmbsrv we can just ignore such locks, 896 * or ignore the part that extends beyond maxoffset. 897 * The SMB layer still keeps track of such locks for 898 * conflict detection, so not reflecting such locks 899 * into the real FS layer is OK. Note: this may 900 * modify the pased bfp->l_len. 901 */ 902 if (bfp->l_start < 0 || bfp->l_start > maxoffset) 903 return (0); 904 if (bfp->l_len < 0 || bfp->l_len > maxoffset) 905 return (0); 906 if (bfp->l_len > (maxoffset - bfp->l_start + 1)) 907 bfp->l_len = (maxoffset - bfp->l_start + 1); 908 909 if (fcntl(vp->v_fd, cmd, bfp) == -1) 910 return (errno); 911 912 return (0); 913 } 914 915 /* ARGSUSED */ 916 int 917 fop_space( 918 vnode_t *vp, 919 int cmd, 920 flock64_t *bfp, 921 int flag, 922 offset_t offset, 923 cred_t *cr, 924 caller_context_t *ct) 925 { 926 /* See fs_frlock */ 927 928 switch (cmd) { 929 case F_ALLOCSP: 930 case F_FREESP: 931 break; 932 default: 933 return (EINVAL); 934 } 935 936 if (fcntl(vp->v_fd, cmd, bfp) == -1) 937 return (errno); 938 939 return (0); 940 } 941 942 /* ARGSUSED */ 943 int 944 fop_realvp( 945 vnode_t *vp, 946 vnode_t **vpp, 947 caller_context_t *ct) 948 { 949 return (ENOSYS); 950 } 951 952 /* ARGSUSED */ 953 int 954 fop_getpage( 955 vnode_t *vp, 956 offset_t off, 957 size_t len, 958 uint_t *protp, 959 struct page **plarr, 960 size_t plsz, 961 struct seg *seg, 962 caddr_t addr, 963 enum seg_rw rw, 964 cred_t *cr, 965 caller_context_t *ct) 966 { 967 return (ENOSYS); 968 } 969 970 /* ARGSUSED */ 971 int 972 fop_putpage( 973 vnode_t *vp, 974 offset_t off, 975 size_t len, 976 int flags, 977 cred_t *cr, 978 caller_context_t *ct) 979 { 980 return (ENOSYS); 981 } 982 983 /* ARGSUSED */ 984 int 985 fop_map( 986 vnode_t *vp, 987 offset_t off, 988 struct as *as, 989 caddr_t *addrp, 990 size_t len, 991 uchar_t prot, 992 uchar_t maxprot, 993 uint_t flags, 994 cred_t *cr, 995 caller_context_t *ct) 996 { 997 return (ENOSYS); 998 } 999 1000 /* ARGSUSED */ 1001 int 1002 fop_addmap( 1003 vnode_t *vp, 1004 offset_t off, 1005 struct as *as, 1006 caddr_t addr, 1007 size_t len, 1008 uchar_t prot, 1009 uchar_t maxprot, 1010 uint_t flags, 1011 cred_t *cr, 1012 caller_context_t *ct) 1013 { 1014 return (ENOSYS); 1015 } 1016 1017 /* ARGSUSED */ 1018 int 1019 fop_delmap( 1020 vnode_t *vp, 1021 offset_t off, 1022 struct as *as, 1023 caddr_t addr, 1024 size_t len, 1025 uint_t prot, 1026 uint_t maxprot, 1027 uint_t flags, 1028 cred_t *cr, 1029 caller_context_t *ct) 1030 { 1031 return (ENOSYS); 1032 } 1033 1034 /* ARGSUSED */ 1035 int 1036 fop_poll( 1037 vnode_t *vp, 1038 short events, 1039 int anyyet, 1040 short *reventsp, 1041 struct pollhead **phpp, 1042 caller_context_t *ct) 1043 { 1044 *reventsp = 0; 1045 if (events & POLLIN) 1046 *reventsp |= POLLIN; 1047 if (events & POLLRDNORM) 1048 *reventsp |= POLLRDNORM; 1049 if (events & POLLRDBAND) 1050 *reventsp |= POLLRDBAND; 1051 if (events & POLLOUT) 1052 *reventsp |= POLLOUT; 1053 if (events & POLLWRBAND) 1054 *reventsp |= POLLWRBAND; 1055 *phpp = NULL; /* or fake_pollhead? */ 1056 1057 return (0); 1058 } 1059 1060 /* ARGSUSED */ 1061 int 1062 fop_dump( 1063 vnode_t *vp, 1064 caddr_t addr, 1065 offset_t lbdn, 1066 offset_t dblks, 1067 caller_context_t *ct) 1068 { 1069 return (ENOSYS); 1070 } 1071 1072 /* 1073 * See fs_pathconf 1074 */ 1075 /* ARGSUSED */ 1076 int 1077 fop_pathconf( 1078 vnode_t *vp, 1079 int cmd, 1080 ulong_t *valp, 1081 cred_t *cr, 1082 caller_context_t *ct) 1083 { 1084 register ulong_t val; 1085 register int error = 0; 1086 1087 switch (cmd) { 1088 1089 case _PC_LINK_MAX: 1090 val = MAXLINK; 1091 break; 1092 1093 case _PC_MAX_CANON: 1094 val = MAX_CANON; 1095 break; 1096 1097 case _PC_MAX_INPUT: 1098 val = MAX_INPUT; 1099 break; 1100 1101 case _PC_NAME_MAX: 1102 val = MAXNAMELEN; 1103 break; 1104 1105 case _PC_PATH_MAX: 1106 case _PC_SYMLINK_MAX: 1107 val = MAXPATHLEN; 1108 break; 1109 1110 case _PC_PIPE_BUF: 1111 val = PIPE_BUF; 1112 break; 1113 1114 case _PC_NO_TRUNC: 1115 val = (ulong_t)-1; 1116 break; 1117 1118 case _PC_VDISABLE: 1119 val = _POSIX_VDISABLE; 1120 break; 1121 1122 case _PC_CHOWN_RESTRICTED: 1123 val = 1; /* chown restricted enabled */ 1124 break; 1125 1126 case _PC_FILESIZEBITS: 1127 val = (ulong_t)-1; /* large file support */ 1128 break; 1129 1130 case _PC_ACL_ENABLED: 1131 val = _ACL_ACE_ENABLED; 1132 break; 1133 1134 case _PC_CASE_BEHAVIOR: 1135 val = _CASE_SENSITIVE; 1136 break; 1137 1138 case _PC_SATTR_ENABLED: 1139 case _PC_SATTR_EXISTS: 1140 val = 0; 1141 break; 1142 1143 case _PC_ACCESS_FILTERING: 1144 val = 0; 1145 break; 1146 1147 default: 1148 error = EINVAL; 1149 break; 1150 } 1151 1152 if (error == 0) 1153 *valp = val; 1154 return (error); 1155 } 1156 1157 /* ARGSUSED */ 1158 int 1159 fop_pageio( 1160 vnode_t *vp, 1161 struct page *pp, 1162 u_offset_t io_off, 1163 size_t io_len, 1164 int flags, 1165 cred_t *cr, 1166 caller_context_t *ct) 1167 { 1168 return (ENOSYS); 1169 } 1170 1171 /* ARGSUSED */ 1172 int 1173 fop_dumpctl( 1174 vnode_t *vp, 1175 int action, 1176 offset_t *blkp, 1177 caller_context_t *ct) 1178 { 1179 return (ENOSYS); 1180 } 1181 1182 /* ARGSUSED */ 1183 void 1184 fop_dispose( 1185 vnode_t *vp, 1186 struct page *pp, 1187 int flag, 1188 int dn, 1189 cred_t *cr, 1190 caller_context_t *ct) 1191 { 1192 } 1193 1194 /* ARGSUSED */ 1195 int 1196 fop_setsecattr( 1197 vnode_t *vp, 1198 vsecattr_t *vsap, 1199 int flag, 1200 cred_t *cr, 1201 caller_context_t *ct) 1202 { 1203 return (0); 1204 } 1205 1206 /* 1207 * Fake up just enough of this so we can test get/set SDs. 1208 */ 1209 /* ARGSUSED */ 1210 int 1211 fop_getsecattr( 1212 vnode_t *vp, 1213 vsecattr_t *vsecattr, 1214 int flag, 1215 cred_t *cr, 1216 caller_context_t *ct) 1217 { 1218 1219 vsecattr->vsa_aclcnt = 0; 1220 vsecattr->vsa_aclentsz = 0; 1221 vsecattr->vsa_aclentp = NULL; 1222 vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */ 1223 vsecattr->vsa_dfaclentp = NULL; 1224 1225 if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) { 1226 aclent_t *aclentp; 1227 size_t aclsize; 1228 1229 aclsize = sizeof (aclent_t); 1230 vsecattr->vsa_aclcnt = 1; 1231 vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 1232 aclentp = vsecattr->vsa_aclentp; 1233 1234 aclentp->a_type = OTHER_OBJ; 1235 aclentp->a_perm = 0777; 1236 aclentp->a_id = (gid_t)-1; 1237 aclentp++; 1238 } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { 1239 ace_t *acl; 1240 1241 acl = kmem_alloc(sizeof (ace_t), KM_SLEEP); 1242 acl->a_who = (uint32_t)-1; 1243 acl->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 1244 acl->a_flags = ACE_EVERYONE; 1245 acl->a_access_mask = ACE_MODIFY_PERMS; 1246 1247 vsecattr->vsa_aclentp = (void *)acl; 1248 vsecattr->vsa_aclcnt = 1; 1249 vsecattr->vsa_aclentsz = sizeof (ace_t); 1250 } 1251 1252 return (0); 1253 } 1254 1255 /* ARGSUSED */ 1256 int 1257 fop_shrlock( 1258 vnode_t *vp, 1259 int cmd, 1260 struct shrlock *shr, 1261 int flag, 1262 cred_t *cr, 1263 caller_context_t *ct) 1264 { 1265 1266 switch (cmd) { 1267 case F_SHARE: 1268 case F_SHARE_NBMAND: 1269 case F_UNSHARE: 1270 break; 1271 default: 1272 return (EINVAL); 1273 } 1274 1275 if (!fop_shrlock_enable) 1276 return (0); 1277 1278 if (fcntl(vp->v_fd, cmd, shr) == -1) 1279 return (errno); 1280 1281 return (0); 1282 } 1283 1284 /* ARGSUSED */ 1285 int 1286 fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm, 1287 caller_context_t *ct) 1288 { 1289 return (ENOSYS); 1290 } 1291 1292 /* ARGSUSED */ 1293 int 1294 fop_reqzcbuf(vnode_t *vp, enum uio_rw ioflag, xuio_t *uiop, cred_t *cr, 1295 caller_context_t *ct) 1296 { 1297 return (ENOSYS); 1298 } 1299 1300 /* ARGSUSED */ 1301 int 1302 fop_retzcbuf(vnode_t *vp, xuio_t *uiop, cred_t *cr, caller_context_t *ct) 1303 { 1304 return (ENOSYS); 1305 } 1306 1307 1308 /* 1309 * *************************************************************** 1310 * other VOP support 1311 */ 1312 1313 /* 1314 * Convert stat(2) formats to vnode types and vice versa. (Knows about 1315 * numerical order of S_IFMT and vnode types.) 1316 */ 1317 enum vtype iftovt_tab[] = { 1318 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 1319 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON 1320 }; 1321 1322 ushort_t vttoif_tab[] = { 1323 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 1324 S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0 1325 }; 1326 1327 /* 1328 * stat_to_vattr() 1329 * 1330 * Convert from a stat structure to an vattr structure 1331 * Note: only set fields according to va_mask 1332 */ 1333 1334 int 1335 stat_to_vattr(const struct stat *st, vattr_t *vap) 1336 { 1337 1338 if (vap->va_mask & AT_TYPE) 1339 vap->va_type = IFTOVT(st->st_mode); 1340 1341 if (vap->va_mask & AT_MODE) 1342 vap->va_mode = st->st_mode; 1343 1344 if (vap->va_mask & AT_UID) 1345 vap->va_uid = st->st_uid; 1346 1347 if (vap->va_mask & AT_GID) 1348 vap->va_gid = st->st_gid; 1349 1350 if (vap->va_mask & AT_FSID) 1351 vap->va_fsid = st->st_dev; 1352 1353 if (vap->va_mask & AT_NODEID) 1354 vap->va_nodeid = st->st_ino; 1355 1356 if (vap->va_mask & AT_NLINK) 1357 vap->va_nlink = st->st_nlink; 1358 1359 if (vap->va_mask & AT_SIZE) 1360 vap->va_size = (u_offset_t)st->st_size; 1361 1362 if (vap->va_mask & AT_ATIME) { 1363 vap->va_atime.tv_sec = st->st_atim.tv_sec; 1364 vap->va_atime.tv_nsec = st->st_atim.tv_nsec; 1365 } 1366 1367 if (vap->va_mask & AT_MTIME) { 1368 vap->va_mtime.tv_sec = st->st_mtim.tv_sec; 1369 vap->va_mtime.tv_nsec = st->st_mtim.tv_nsec; 1370 } 1371 1372 if (vap->va_mask & AT_CTIME) { 1373 vap->va_ctime.tv_sec = st->st_ctim.tv_sec; 1374 vap->va_ctime.tv_nsec = st->st_ctim.tv_nsec; 1375 } 1376 1377 if (vap->va_mask & AT_RDEV) 1378 vap->va_rdev = st->st_rdev; 1379 1380 if (vap->va_mask & AT_BLKSIZE) 1381 vap->va_blksize = (uint_t)st->st_blksize; 1382 1383 1384 if (vap->va_mask & AT_NBLOCKS) 1385 vap->va_nblocks = (u_longlong_t)st->st_blocks; 1386 1387 if (vap->va_mask & AT_SEQ) 1388 vap->va_seq = 0; 1389 1390 return (0); 1391 } 1392 1393 /* ARGSUSED */ 1394 void 1395 flk_init_callback(flk_callback_t *flk_cb, 1396 callb_cpr_t *(*cb_fcn)(flk_cb_when_t, void *), void *cbdata) 1397 { 1398 } 1399 1400 void 1401 vn_hold(vnode_t *vp) 1402 { 1403 mutex_enter(&vp->v_lock); 1404 vp->v_count++; 1405 mutex_exit(&vp->v_lock); 1406 } 1407 1408 void 1409 vn_rele(vnode_t *vp) 1410 { 1411 VERIFY3U(vp->v_count, !=, 0); 1412 mutex_enter(&vp->v_lock); 1413 if (vp->v_count == 1) { 1414 mutex_exit(&vp->v_lock); 1415 fop_inactive(vp, NULL, NULL); 1416 } else { 1417 vp->v_count--; 1418 mutex_exit(&vp->v_lock); 1419 } 1420 } 1421 1422 int 1423 vn_has_other_opens( 1424 vnode_t *vp, 1425 v_mode_t mode) 1426 { 1427 1428 switch (mode) { 1429 case V_WRITE: 1430 if (vp->v_wrcnt > 1) 1431 return (V_TRUE); 1432 break; 1433 case V_RDORWR: 1434 if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1)) 1435 return (V_TRUE); 1436 break; 1437 case V_RDANDWR: 1438 if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1)) 1439 return (V_TRUE); 1440 break; 1441 case V_READ: 1442 if (vp->v_rdcnt > 1) 1443 return (V_TRUE); 1444 break; 1445 } 1446 1447 return (V_FALSE); 1448 } 1449 1450 /* 1451 * vn_is_opened() checks whether a particular file is opened and 1452 * whether the open is for read and/or write. 1453 * 1454 * Vnode counts are only kept on regular files (v_type=VREG). 1455 */ 1456 int 1457 vn_is_opened( 1458 vnode_t *vp, 1459 v_mode_t mode) 1460 { 1461 1462 ASSERT(vp != NULL); 1463 1464 switch (mode) { 1465 case V_WRITE: 1466 if (vp->v_wrcnt) 1467 return (V_TRUE); 1468 break; 1469 case V_RDANDWR: 1470 if (vp->v_rdcnt && vp->v_wrcnt) 1471 return (V_TRUE); 1472 break; 1473 case V_RDORWR: 1474 if (vp->v_rdcnt || vp->v_wrcnt) 1475 return (V_TRUE); 1476 break; 1477 case V_READ: 1478 if (vp->v_rdcnt) 1479 return (V_TRUE); 1480 break; 1481 } 1482 1483 return (V_FALSE); 1484 } 1485 1486 /* 1487 * vn_is_mapped() checks whether a particular file is mapped and whether 1488 * the file is mapped read and/or write. 1489 */ 1490 /* ARGSUSED */ 1491 int 1492 vn_is_mapped( 1493 vnode_t *vp, 1494 v_mode_t mode) 1495 { 1496 return (V_FALSE); 1497 } 1498