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