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 /* See fs_frlock */ 862 863 switch (cmd) { 864 case F_GETLK: 865 case F_SETLK_NBMAND: 866 case F_SETLK: 867 case F_SETLKW: 868 break; 869 default: 870 return (EINVAL); 871 } 872 873 if (fcntl(vp->v_fd, cmd, bfp) == -1) 874 return (errno); 875 876 return (0); 877 } 878 879 /* ARGSUSED */ 880 int 881 fop_space( 882 vnode_t *vp, 883 int cmd, 884 flock64_t *bfp, 885 int flag, 886 offset_t offset, 887 cred_t *cr, 888 caller_context_t *ct) 889 { 890 /* See fs_frlock */ 891 892 switch (cmd) { 893 case F_ALLOCSP: 894 case F_FREESP: 895 break; 896 default: 897 return (EINVAL); 898 } 899 900 if (fcntl(vp->v_fd, cmd, bfp) == -1) 901 return (errno); 902 903 return (0); 904 } 905 906 /* ARGSUSED */ 907 int 908 fop_realvp( 909 vnode_t *vp, 910 vnode_t **vpp, 911 caller_context_t *ct) 912 { 913 return (ENOSYS); 914 } 915 916 /* ARGSUSED */ 917 int 918 fop_getpage( 919 vnode_t *vp, 920 offset_t off, 921 size_t len, 922 uint_t *protp, 923 struct page **plarr, 924 size_t plsz, 925 struct seg *seg, 926 caddr_t addr, 927 enum seg_rw rw, 928 cred_t *cr, 929 caller_context_t *ct) 930 { 931 return (ENOSYS); 932 } 933 934 /* ARGSUSED */ 935 int 936 fop_putpage( 937 vnode_t *vp, 938 offset_t off, 939 size_t len, 940 int flags, 941 cred_t *cr, 942 caller_context_t *ct) 943 { 944 return (ENOSYS); 945 } 946 947 /* ARGSUSED */ 948 int 949 fop_map( 950 vnode_t *vp, 951 offset_t off, 952 struct as *as, 953 caddr_t *addrp, 954 size_t len, 955 uchar_t prot, 956 uchar_t maxprot, 957 uint_t flags, 958 cred_t *cr, 959 caller_context_t *ct) 960 { 961 return (ENOSYS); 962 } 963 964 /* ARGSUSED */ 965 int 966 fop_addmap( 967 vnode_t *vp, 968 offset_t off, 969 struct as *as, 970 caddr_t addr, 971 size_t len, 972 uchar_t prot, 973 uchar_t maxprot, 974 uint_t flags, 975 cred_t *cr, 976 caller_context_t *ct) 977 { 978 return (ENOSYS); 979 } 980 981 /* ARGSUSED */ 982 int 983 fop_delmap( 984 vnode_t *vp, 985 offset_t off, 986 struct as *as, 987 caddr_t addr, 988 size_t len, 989 uint_t prot, 990 uint_t maxprot, 991 uint_t flags, 992 cred_t *cr, 993 caller_context_t *ct) 994 { 995 return (ENOSYS); 996 } 997 998 /* ARGSUSED */ 999 int 1000 fop_poll( 1001 vnode_t *vp, 1002 short events, 1003 int anyyet, 1004 short *reventsp, 1005 struct pollhead **phpp, 1006 caller_context_t *ct) 1007 { 1008 *reventsp = 0; 1009 if (events & POLLIN) 1010 *reventsp |= POLLIN; 1011 if (events & POLLRDNORM) 1012 *reventsp |= POLLRDNORM; 1013 if (events & POLLRDBAND) 1014 *reventsp |= POLLRDBAND; 1015 if (events & POLLOUT) 1016 *reventsp |= POLLOUT; 1017 if (events & POLLWRBAND) 1018 *reventsp |= POLLWRBAND; 1019 *phpp = NULL; /* or fake_pollhead? */ 1020 1021 return (0); 1022 } 1023 1024 /* ARGSUSED */ 1025 int 1026 fop_dump( 1027 vnode_t *vp, 1028 caddr_t addr, 1029 offset_t lbdn, 1030 offset_t dblks, 1031 caller_context_t *ct) 1032 { 1033 return (ENOSYS); 1034 } 1035 1036 /* 1037 * See fs_pathconf 1038 */ 1039 /* ARGSUSED */ 1040 int 1041 fop_pathconf( 1042 vnode_t *vp, 1043 int cmd, 1044 ulong_t *valp, 1045 cred_t *cr, 1046 caller_context_t *ct) 1047 { 1048 register ulong_t val; 1049 register int error = 0; 1050 1051 switch (cmd) { 1052 1053 case _PC_LINK_MAX: 1054 val = MAXLINK; 1055 break; 1056 1057 case _PC_MAX_CANON: 1058 val = MAX_CANON; 1059 break; 1060 1061 case _PC_MAX_INPUT: 1062 val = MAX_INPUT; 1063 break; 1064 1065 case _PC_NAME_MAX: 1066 val = MAXNAMELEN; 1067 break; 1068 1069 case _PC_PATH_MAX: 1070 case _PC_SYMLINK_MAX: 1071 val = MAXPATHLEN; 1072 break; 1073 1074 case _PC_PIPE_BUF: 1075 val = PIPE_BUF; 1076 break; 1077 1078 case _PC_NO_TRUNC: 1079 val = (ulong_t)-1; 1080 break; 1081 1082 case _PC_VDISABLE: 1083 val = _POSIX_VDISABLE; 1084 break; 1085 1086 case _PC_CHOWN_RESTRICTED: 1087 val = 1; /* chown restricted enabled */ 1088 break; 1089 1090 case _PC_FILESIZEBITS: 1091 val = (ulong_t)-1; /* large file support */ 1092 break; 1093 1094 case _PC_ACL_ENABLED: 1095 val = 0; 1096 break; 1097 1098 case _PC_CASE_BEHAVIOR: 1099 val = _CASE_SENSITIVE; 1100 break; 1101 1102 case _PC_SATTR_ENABLED: 1103 case _PC_SATTR_EXISTS: 1104 val = 0; 1105 break; 1106 1107 case _PC_ACCESS_FILTERING: 1108 val = 0; 1109 break; 1110 1111 default: 1112 error = EINVAL; 1113 break; 1114 } 1115 1116 if (error == 0) 1117 *valp = val; 1118 return (error); 1119 } 1120 1121 /* ARGSUSED */ 1122 int 1123 fop_pageio( 1124 vnode_t *vp, 1125 struct page *pp, 1126 u_offset_t io_off, 1127 size_t io_len, 1128 int flags, 1129 cred_t *cr, 1130 caller_context_t *ct) 1131 { 1132 return (ENOSYS); 1133 } 1134 1135 /* ARGSUSED */ 1136 int 1137 fop_dumpctl( 1138 vnode_t *vp, 1139 int action, 1140 offset_t *blkp, 1141 caller_context_t *ct) 1142 { 1143 return (ENOSYS); 1144 } 1145 1146 /* ARGSUSED */ 1147 void 1148 fop_dispose( 1149 vnode_t *vp, 1150 struct page *pp, 1151 int flag, 1152 int dn, 1153 cred_t *cr, 1154 caller_context_t *ct) 1155 { 1156 } 1157 1158 /* ARGSUSED */ 1159 int 1160 fop_setsecattr( 1161 vnode_t *vp, 1162 vsecattr_t *vsap, 1163 int flag, 1164 cred_t *cr, 1165 caller_context_t *ct) 1166 { 1167 return (0); 1168 } 1169 1170 /* 1171 * Fake up just enough of this so we can test get/set SDs. 1172 */ 1173 /* ARGSUSED */ 1174 int 1175 fop_getsecattr( 1176 vnode_t *vp, 1177 vsecattr_t *vsecattr, 1178 int flag, 1179 cred_t *cr, 1180 caller_context_t *ct) 1181 { 1182 1183 vsecattr->vsa_aclcnt = 0; 1184 vsecattr->vsa_aclentsz = 0; 1185 vsecattr->vsa_aclentp = NULL; 1186 vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */ 1187 vsecattr->vsa_dfaclentp = NULL; 1188 1189 if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) { 1190 aclent_t *aclentp; 1191 size_t aclsize; 1192 1193 aclsize = sizeof (aclent_t); 1194 vsecattr->vsa_aclcnt = 1; 1195 vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 1196 aclentp = vsecattr->vsa_aclentp; 1197 1198 aclentp->a_type = OTHER_OBJ; 1199 aclentp->a_perm = 0777; 1200 aclentp->a_id = (gid_t)-1; 1201 aclentp++; 1202 } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { 1203 ace_t *acl; 1204 1205 acl = kmem_alloc(sizeof (ace_t), KM_SLEEP); 1206 acl->a_who = (uint32_t)-1; 1207 acl->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 1208 acl->a_flags = ACE_EVERYONE; 1209 acl->a_access_mask = ACE_MODIFY_PERMS; 1210 1211 vsecattr->vsa_aclentp = (void *)acl; 1212 vsecattr->vsa_aclcnt = 1; 1213 vsecattr->vsa_aclentsz = sizeof (ace_t); 1214 } 1215 1216 return (0); 1217 } 1218 1219 /* ARGSUSED */ 1220 int 1221 fop_shrlock( 1222 vnode_t *vp, 1223 int cmd, 1224 struct shrlock *shr, 1225 int flag, 1226 cred_t *cr, 1227 caller_context_t *ct) 1228 { 1229 1230 switch (cmd) { 1231 case F_SHARE: 1232 case F_SHARE_NBMAND: 1233 case F_UNSHARE: 1234 break; 1235 default: 1236 return (EINVAL); 1237 } 1238 1239 if (!fop_shrlock_enable) 1240 return (0); 1241 1242 if (fcntl(vp->v_fd, cmd, shr) == -1) 1243 return (errno); 1244 1245 return (0); 1246 } 1247 1248 /* ARGSUSED */ 1249 int 1250 fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm, 1251 caller_context_t *ct) 1252 { 1253 return (ENOSYS); 1254 } 1255 1256 /* ARGSUSED */ 1257 int 1258 fop_reqzcbuf(vnode_t *vp, enum uio_rw ioflag, xuio_t *uiop, cred_t *cr, 1259 caller_context_t *ct) 1260 { 1261 return (ENOSYS); 1262 } 1263 1264 /* ARGSUSED */ 1265 int 1266 fop_retzcbuf(vnode_t *vp, xuio_t *uiop, cred_t *cr, caller_context_t *ct) 1267 { 1268 return (ENOSYS); 1269 } 1270 1271 1272 /* 1273 * *************************************************************** 1274 * other VOP support 1275 */ 1276 1277 /* 1278 * Convert stat(2) formats to vnode types and vice versa. (Knows about 1279 * numerical order of S_IFMT and vnode types.) 1280 */ 1281 enum vtype iftovt_tab[] = { 1282 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 1283 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON 1284 }; 1285 1286 ushort_t vttoif_tab[] = { 1287 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 1288 S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0 1289 }; 1290 1291 /* 1292 * stat_to_vattr() 1293 * 1294 * Convert from a stat structure to an vattr structure 1295 * Note: only set fields according to va_mask 1296 */ 1297 1298 int 1299 stat_to_vattr(const struct stat *st, vattr_t *vap) 1300 { 1301 1302 if (vap->va_mask & AT_TYPE) 1303 vap->va_type = IFTOVT(st->st_mode); 1304 1305 if (vap->va_mask & AT_MODE) 1306 vap->va_mode = st->st_mode; 1307 1308 if (vap->va_mask & AT_UID) 1309 vap->va_uid = st->st_uid; 1310 1311 if (vap->va_mask & AT_GID) 1312 vap->va_gid = st->st_gid; 1313 1314 if (vap->va_mask & AT_FSID) 1315 vap->va_fsid = st->st_dev; 1316 1317 if (vap->va_mask & AT_NODEID) 1318 vap->va_nodeid = st->st_ino; 1319 1320 if (vap->va_mask & AT_NLINK) 1321 vap->va_nlink = st->st_nlink; 1322 1323 if (vap->va_mask & AT_SIZE) 1324 vap->va_size = (u_offset_t)st->st_size; 1325 1326 if (vap->va_mask & AT_ATIME) { 1327 vap->va_atime.tv_sec = st->st_atim.tv_sec; 1328 vap->va_atime.tv_nsec = st->st_atim.tv_nsec; 1329 } 1330 1331 if (vap->va_mask & AT_MTIME) { 1332 vap->va_mtime.tv_sec = st->st_mtim.tv_sec; 1333 vap->va_mtime.tv_nsec = st->st_mtim.tv_nsec; 1334 } 1335 1336 if (vap->va_mask & AT_CTIME) { 1337 vap->va_ctime.tv_sec = st->st_ctim.tv_sec; 1338 vap->va_ctime.tv_nsec = st->st_ctim.tv_nsec; 1339 } 1340 1341 if (vap->va_mask & AT_RDEV) 1342 vap->va_rdev = st->st_rdev; 1343 1344 if (vap->va_mask & AT_BLKSIZE) 1345 vap->va_blksize = (uint_t)st->st_blksize; 1346 1347 1348 if (vap->va_mask & AT_NBLOCKS) 1349 vap->va_nblocks = (u_longlong_t)st->st_blocks; 1350 1351 if (vap->va_mask & AT_SEQ) 1352 vap->va_seq = 0; 1353 1354 return (0); 1355 } 1356 1357 /* ARGSUSED */ 1358 void 1359 flk_init_callback(flk_callback_t *flk_cb, 1360 callb_cpr_t *(*cb_fcn)(flk_cb_when_t, void *), void *cbdata) 1361 { 1362 } 1363 1364 void 1365 vn_hold(vnode_t *vp) 1366 { 1367 mutex_enter(&vp->v_lock); 1368 vp->v_count++; 1369 mutex_exit(&vp->v_lock); 1370 } 1371 1372 void 1373 vn_rele(vnode_t *vp) 1374 { 1375 VERIFY3U(vp->v_count, !=, 0); 1376 mutex_enter(&vp->v_lock); 1377 if (vp->v_count == 1) { 1378 mutex_exit(&vp->v_lock); 1379 fop_inactive(vp, NULL, NULL); 1380 } else { 1381 vp->v_count--; 1382 mutex_exit(&vp->v_lock); 1383 } 1384 } 1385 1386 int 1387 vn_has_other_opens( 1388 vnode_t *vp, 1389 v_mode_t mode) 1390 { 1391 1392 switch (mode) { 1393 case V_WRITE: 1394 if (vp->v_wrcnt > 1) 1395 return (V_TRUE); 1396 break; 1397 case V_RDORWR: 1398 if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1)) 1399 return (V_TRUE); 1400 break; 1401 case V_RDANDWR: 1402 if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1)) 1403 return (V_TRUE); 1404 break; 1405 case V_READ: 1406 if (vp->v_rdcnt > 1) 1407 return (V_TRUE); 1408 break; 1409 } 1410 1411 return (V_FALSE); 1412 } 1413 1414 /* 1415 * vn_is_opened() checks whether a particular file is opened and 1416 * whether the open is for read and/or write. 1417 * 1418 * Vnode counts are only kept on regular files (v_type=VREG). 1419 */ 1420 int 1421 vn_is_opened( 1422 vnode_t *vp, 1423 v_mode_t mode) 1424 { 1425 1426 ASSERT(vp != NULL); 1427 1428 switch (mode) { 1429 case V_WRITE: 1430 if (vp->v_wrcnt) 1431 return (V_TRUE); 1432 break; 1433 case V_RDANDWR: 1434 if (vp->v_rdcnt && vp->v_wrcnt) 1435 return (V_TRUE); 1436 break; 1437 case V_RDORWR: 1438 if (vp->v_rdcnt || vp->v_wrcnt) 1439 return (V_TRUE); 1440 break; 1441 case V_READ: 1442 if (vp->v_rdcnt) 1443 return (V_TRUE); 1444 break; 1445 } 1446 1447 return (V_FALSE); 1448 } 1449 1450 /* 1451 * vn_is_mapped() checks whether a particular file is mapped and whether 1452 * the file is mapped read and/or write. 1453 */ 1454 /* ARGSUSED */ 1455 int 1456 vn_is_mapped( 1457 vnode_t *vp, 1458 v_mode_t mode) 1459 { 1460 return (V_FALSE); 1461 } 1462