Print this page
*** NO COMMENTS ***

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
          +++ new/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
↓ open down ↓ 43 lines elided ↑ open up ↑
  44   44  #include <sys/uio.h>
  45   45  #include <sys/dirent.h>
  46   46  #include <sys/errno.h>
  47   47  #include <sys/sunddi.h>
  48   48  #include <sys/sysmacros.h>
  49   49  #include <sys/kmem.h>
  50   50  #include <sys/cmn_err.h>
  51   51  #include <sys/vfs_opreg.h>
  52   52  #include <sys/policy.h>
  53   53  
       54 +#include <sys/param.h>
       55 +#include <sys/vm.h>
       56 +#include <vm/seg_vn.h>
       57 +#include <vm/pvn.h>
       58 +#include <vm/as.h>
       59 +#include <vm/hat.h>
       60 +#include <vm/page.h>
       61 +#include <vm/seg.h>
       62 +#include <vm/seg_map.h>
       63 +#include <vm/seg_kmem.h>
       64 +#include <vm/seg_kpm.h>
       65 +
  54   66  #include <netsmb/smb_osdep.h>
  55   67  #include <netsmb/smb.h>
  56   68  #include <netsmb/smb_conn.h>
  57   69  #include <netsmb/smb_subr.h>
  58   70  
  59   71  #include <smbfs/smbfs.h>
  60   72  #include <smbfs/smbfs_node.h>
  61   73  #include <smbfs/smbfs_subr.h>
  62   74  
  63   75  #include <sys/fs/smbfs_ioctl.h>
↓ open down ↓ 104 lines elided ↑ open up ↑
 168  180                          cred_t *, caller_context_t *);
 169  181  static int      smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 170  182                          caller_context_t *);
 171  183  static int      smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 172  184                          caller_context_t *);
 173  185  static int      smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 174  186                          caller_context_t *);
 175  187  static int      smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 176  188                          caller_context_t *);
 177  189  
      190 +static int uio_page_mapin(uio_t *uiop, page_t *pp);
      191 +
      192 +static void uio_page_mapout(uio_t *uiop, page_t *pp);
      193 +
      194 +static int smbfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
      195 +        size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
      196 +        caller_context_t *ct);
      197 +
      198 +static int smbfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
      199 +        size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
      200 +        caller_context_t *ct);
      201 +
      202 +static int smbfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
      203 +        size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
      204 +        caller_context_t *ct);
      205 +
      206 +static int smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags,
      207 +        cred_t *cr, caller_context_t *ct);
      208 +
      209 +static int smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
      210 +        int flags, cred_t *cr);
      211 +
      212 +static int smbfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
      213 +        page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
      214 +        enum seg_rw rw, cred_t *cr, caller_context_t *ct);
      215 +
      216 +static int smbfs_getapage(vnode_t *vp, u_offset_t off, size_t len,
      217 +        uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
      218 +        enum seg_rw rw, cred_t *cr);
      219 +
      220 +static int writenp(smbnode_t *np, caddr_t base, int tcount, struct uio *uiop, int pgcreated);
      221 +
 178  222  /* Dummy function to use until correct function is ported in */
 179  223  int noop_vnodeop() {
 180  224          return (0);
 181  225  }
 182  226  
 183  227  struct vnodeops *smbfs_vnodeops = NULL;
 184  228  
 185  229  /*
 186  230   * Most unimplemented ops will return ENOSYS because of fs_nosys().
 187  231   * The only ops where that won't work are ACCESS (due to open(2)
↓ open down ↓ 20 lines elided ↑ open up ↑
 208  252          { VOPNAME_READLINK,     { .error = fs_nosys } }, /* smbfs_readlink, */
 209  253          { VOPNAME_FSYNC,        { .vop_fsync = smbfs_fsync } },
 210  254          { VOPNAME_INACTIVE,     { .vop_inactive = smbfs_inactive } },
 211  255          { VOPNAME_FID,          { .error = fs_nosys } }, /* smbfs_fid, */
 212  256          { VOPNAME_RWLOCK,       { .vop_rwlock = smbfs_rwlock } },
 213  257          { VOPNAME_RWUNLOCK,     { .vop_rwunlock = smbfs_rwunlock } },
 214  258          { VOPNAME_SEEK,         { .vop_seek = smbfs_seek } },
 215  259          { VOPNAME_FRLOCK,       { .vop_frlock = smbfs_frlock } },
 216  260          { VOPNAME_SPACE,        { .vop_space = smbfs_space } },
 217  261          { VOPNAME_REALVP,       { .error = fs_nosys } }, /* smbfs_realvp, */
 218      -        { VOPNAME_GETPAGE,      { .error = fs_nosys } }, /* smbfs_getpage, */
 219      -        { VOPNAME_PUTPAGE,      { .error = fs_nosys } }, /* smbfs_putpage, */
 220      -        { VOPNAME_MAP,          { .error = fs_nosys } }, /* smbfs_map, */
 221      -        { VOPNAME_ADDMAP,       { .error = fs_nosys } }, /* smbfs_addmap, */
 222      -        { VOPNAME_DELMAP,       { .error = fs_nosys } }, /* smbfs_delmap, */
      262 +        { VOPNAME_GETPAGE,      { .vop_getpage = smbfs_getpage } }, /* smbfs_getpage, */
      263 +        { VOPNAME_PUTPAGE,      { .vop_putpage = smbfs_putpage } }, /* smbfs_putpage, */
      264 +        { VOPNAME_MAP,          { .vop_map = smbfs_map } }, /* smbfs_map, */
      265 +        { VOPNAME_ADDMAP,       { .vop_addmap = smbfs_addmap } }, /* smbfs_addmap, */
      266 +        { VOPNAME_DELMAP,       { .vop_delmap = smbfs_delmap } }, /* smbfs_delmap, */
      267 +        { VOPNAME_DISPOSE,      { .vop_dispose = fs_dispose}},
 223  268          { VOPNAME_DUMP,         { .error = fs_nosys } }, /* smbfs_dump, */
 224  269          { VOPNAME_PATHCONF,     { .vop_pathconf = smbfs_pathconf } },
 225  270          { VOPNAME_PAGEIO,       { .error = fs_nosys } }, /* smbfs_pageio, */
 226  271          { VOPNAME_SETSECATTR,   { .vop_setsecattr = smbfs_setsecattr } },
 227  272          { VOPNAME_GETSECATTR,   { .vop_getsecattr = smbfs_getsecattr } },
 228  273          { VOPNAME_SHRLOCK,      { .vop_shrlock = smbfs_shrlock } },
 229  274          { NULL, NULL }
 230  275  };
 231  276  
 232  277  /*
↓ open down ↓ 246 lines elided ↑ open up ↑
 479  524          /*
 480  525           * Decrement the reference count for the FID
 481  526           * and possibly do the OtW close.
 482  527           *
 483  528           * Exclusive lock for modifying n_fid stuff.
 484  529           * Don't want this one ever interruptible.
 485  530           */
 486  531          (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
 487  532          smb_credinit(&scred, cr);
 488  533  
 489      -        smbfs_rele_fid(np, &scred);
      534 +        /*
      535 +         * If FID ref. count is 1 and count of mmaped pages isn't 0,
      536 +         * we won't call smbfs_rele_fid(), because it will result in the otW close.
      537 +         * The count of mapped pages isn't 0, which means the mapped pages
      538 +         * possibly will be accessed after close(), we should keep the FID valid,
      539 +         * i.e., dont do the otW close.
      540 +         * Dont worry that FID will be leaked, because when the
      541 +         * vnode's count becomes 0, smbfs_inactive() will
      542 +         * help us release FID and eventually do the otW close.
      543 +         */
      544 +        if (np->n_fidrefs > 1) {
      545 +                smbfs_rele_fid(np, &scred);
      546 +        } else if (np->r_mapcnt == 0) {
      547 +                /*
      548 +                 * Before otW close, make sure dirty pages written back.
      549 +                 */
      550 +                if ((flag & FWRITE) && vn_has_cached_data(vp)) {
      551 +                        /* smbfs_putapage() will acquire shared lock, so release
      552 +                         * exclusive lock temporally.
      553 +                         */
      554 +                        smbfs_rw_exit(&np->r_lkserlock);
      555 +
      556 +                        (void) smbfs_putpage(vp, (offset_t) 0, 0, B_INVAL | B_ASYNC, cr, ct);
      557 +
      558 +                        /* acquire exclusive lock again. */
      559 +                        (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
      560 +                }
      561 +                smbfs_rele_fid(np, &scred);
      562 +        }
 490  563  
 491  564          smb_credrele(&scred);
 492  565          smbfs_rw_exit(&np->r_lkserlock);
 493  566  
 494  567          return (0);
 495  568  }
 496  569  
 497  570  /*
 498  571   * Helper for smbfs_close.  Decrement the reference count
 499  572   * for an SMB-level file or directory ID, and when the last
↓ open down ↓ 68 lines elided ↑ open up ↑
 568  641                  smbfs_attrcache_rm_locked(np);
 569  642          oldcr = np->r_cred;
 570  643          np->r_cred = NULL;
 571  644          mutex_exit(&np->r_statelock);
 572  645          if (oldcr != NULL)
 573  646                  crfree(oldcr);
 574  647  }
 575  648  
 576  649  /* ARGSUSED */
 577  650  static int
 578      -smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 579      -        caller_context_t *ct)
      651 +smbfs_read(vnode_t * vp, struct uio * uiop, int ioflag, cred_t * cr,
      652 +           caller_context_t * ct)
 580  653  {
 581  654          struct smb_cred scred;
 582      -        struct vattr    va;
 583      -        smbnode_t       *np;
 584      -        smbmntinfo_t    *smi;
 585      -        smb_share_t     *ssp;
 586      -        offset_t        endoff;
 587      -        ssize_t         past_eof;
 588      -        int             error;
      655 +        struct vattr    va;
      656 +        smbnode_t      *np;
      657 +        smbmntinfo_t   *smi;
      658 +        smb_share_t    *ssp;
      659 +        offset_t        endoff;
      660 +        ssize_t         past_eof;
      661 +        int             error;
      662 +
      663 +        caddr_t         base;
      664 +        u_offset_t      blk;
      665 +        u_offset_t      boff;
      666 +        size_t          blen;
      667 +        uint_t          flags;
 589  668  
 590  669          np = VTOSMB(vp);
 591  670          smi = VTOSMI(vp);
 592  671          ssp = smi->smi_share;
 593  672  
 594  673          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 595  674                  return (EIO);
 596  675  
 597  676          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 598  677                  return (EIO);
 599  678  
 600  679          ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
 601  680  
 602  681          if (vp->v_type != VREG)
 603  682                  return (EISDIR);
 604  683  
 605  684          if (uiop->uio_resid == 0)
 606  685                  return (0);
 607  686  
 608  687          /*
 609      -         * Like NFS3, just check for 63-bit overflow.
 610      -         * Our SMB layer takes care to return EFBIG
 611      -         * when it has to fallback to a 32-bit call.
      688 +         * Like NFS3, just check for 63-bit overflow. Our SMB layer takes
      689 +         * care to return EFBIG when it has to fallback to a 32-bit call.
 612  690           */
 613  691          endoff = uiop->uio_loffset + uiop->uio_resid;
 614  692          if (uiop->uio_loffset < 0 || endoff < 0)
 615  693                  return (EINVAL);
 616  694  
 617  695          /* get vnode attributes from server */
 618  696          va.va_mask = AT_SIZE | AT_MTIME;
 619  697          if (error = smbfsgetattr(vp, &va, cr))
 620  698                  return (error);
 621  699  
 622  700          /* Update mtime with mtime from server here? */
 623  701  
 624  702          /* if offset is beyond EOF, read nothing */
 625  703          if (uiop->uio_loffset >= va.va_size)
 626  704                  return (0);
 627  705  
 628  706          /*
 629      -         * Limit the read to the remaining file size.
 630      -         * Do this by temporarily reducing uio_resid
 631      -         * by the amount the lies beyoned the EOF.
      707 +         * Limit the read to the remaining file size. Do this by temporarily
      708 +         * reducing uio_resid by the amount the lies beyoned the EOF.
 632  709           */
 633  710          if (endoff > va.va_size) {
 634      -                past_eof = (ssize_t)(endoff - va.va_size);
      711 +                past_eof = (ssize_t) (endoff - va.va_size);
 635  712                  uiop->uio_resid -= past_eof;
 636  713          } else
 637  714                  past_eof = 0;
 638  715  
 639      -        /* Shared lock for n_fid use in smb_rwuio */
 640      -        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 641      -                return (EINTR);
 642      -        smb_credinit(&scred, cr);
      716 +        /* Bypass the VM if vnode is non-cacheable. */
      717 +        if ((vp->v_flag & VNOCACHE) ||
      718 +            ((np->r_flags & RDIRECTIO) &&
      719 +             np->r_mapcnt == 0 &&
      720 +             !(vn_has_cached_data(vp)))) {
 643  721  
 644      -        /* After reconnect, n_fid is invalid */
 645      -        if (np->n_vcgenid != ssp->ss_vcgenid)
 646      -                error = ESTALE;
 647      -        else
 648      -                error = smb_rwuio(ssp, np->n_fid, UIO_READ,
 649      -                    uiop, &scred, smb_timo_read);
      722 +                /* Shared lock for n_fid use in smb_rwuio */
      723 +                if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
      724 +                        return (EINTR);
      725 +                smb_credinit(&scred, cr);
 650  726  
 651      -        smb_credrele(&scred);
 652      -        smbfs_rw_exit(&np->r_lkserlock);
      727 +                /* After reconnect, n_fid is invalid */
      728 +                if (np->n_vcgenid != ssp->ss_vcgenid)
      729 +                        error = ESTALE;
      730 +                else
      731 +                        error = smb_rwuio(ssp, np->n_fid, UIO_READ,
      732 +                                          uiop, &scred, smb_timo_read);
      733 +
      734 +                smb_credrele(&scred);
      735 +                smbfs_rw_exit(&np->r_lkserlock);
      736 +
      737 +        } else {
      738 +
      739 +                /* Do I/O through segmap. */
      740 +                do {
      741 +                        blk = uiop->uio_loffset & MAXBMASK;
      742 +                        boff = uiop->uio_loffset & MAXBOFFSET;
      743 +                        blen = MIN(MAXBSIZE - boff, uiop->uio_resid);
      744 +
      745 +                        if (vpm_enable) {
      746 +
      747 +                                error = vpm_data_copy(vp, blk + boff, blen, uiop, 1, NULL, 0, S_READ);
      748 +
      749 +                        } else {
      750 +
      751 +                                base = segmap_getmapflt(segkmap, vp, blk + boff, blen, 1, S_READ);
      752 +
      753 +                                error = uiomove(base + boff, blen, UIO_READ, uiop);
      754 +                        }
      755 +
      756 +                        if (!error) {
      757 +                                mutex_enter(&np->r_statelock);
      758 +                                if ((blen + boff == MAXBSIZE) || (uiop->uio_loffset == np->r_size)) {
      759 +                                        flags = SM_DONTNEED;
      760 +                                } else {
      761 +                                        flags = 0;
      762 +                                }
      763 +                                mutex_exit(&np->r_statelock);
      764 +                        } else {
      765 +                                flags = 0;
      766 +                        }
      767 +                        if (vpm_enable) {
      768 +                                (void) vpm_sync_pages(vp, blk + boff, blen, flags);
      769 +                        } else {
      770 +                                (void) segmap_release(segkmap, base, flags);
      771 +                        }
      772 +                } while (!error && uiop->uio_resid > 0);
      773 +        }
 653  774  
 654  775          /* undo adjustment of resid */
 655  776          uiop->uio_resid += past_eof;
 656  777  
 657  778          return (error);
 658  779  }
 659  780  
 660      -
 661  781  /* ARGSUSED */
 662  782  static int
 663      -smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 664      -        caller_context_t *ct)
      783 +smbfs_write(vnode_t * vp, struct uio * uiop, int ioflag, cred_t * cr,
      784 +            caller_context_t * ct)
 665  785  {
 666  786          struct smb_cred scred;
 667      -        struct vattr    va;
 668      -        smbnode_t       *np;
 669      -        smbmntinfo_t    *smi;
 670      -        smb_share_t     *ssp;
 671      -        offset_t        endoff, limit;
 672      -        ssize_t         past_limit;
 673      -        int             error, timo;
      787 +        struct vattr    va;
      788 +        smbnode_t      *np;
      789 +        smbmntinfo_t   *smi;
      790 +        smb_share_t    *ssp;
      791 +        offset_t        endoff, limit;
      792 +        ssize_t         past_limit;
      793 +        int             error, timo;
      794 +
      795 +        caddr_t         base;
      796 +        u_offset_t      blk;
      797 +        u_offset_t      boff;
      798 +        size_t          blen;
      799 +        uint_t          flags;
      800 +
      801 +        u_offset_t      last_off;
      802 +        size_t          last_resid;
 674  803  
 675  804          np = VTOSMB(vp);
 676  805          smi = VTOSMI(vp);
 677  806          ssp = smi->smi_share;
 678  807  
 679  808          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 680  809                  return (EIO);
 681  810  
 682  811          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 683  812                  return (EIO);
↓ open down ↓ 17 lines elided ↑ open up ↑
 701  830          }
 702  831          if (ioflag & FAPPEND) {
 703  832                  /*
 704  833                   * File size can be changed by another client
 705  834                   */
 706  835                  va.va_mask = AT_SIZE;
 707  836                  if (error = smbfsgetattr(vp, &va, cr))
 708  837                          return (error);
 709  838                  uiop->uio_loffset = va.va_size;
 710  839          }
 711      -
 712  840          /*
 713  841           * Like NFS3, just check for 63-bit overflow.
 714  842           */
 715  843          endoff = uiop->uio_loffset + uiop->uio_resid;
 716  844          if (uiop->uio_loffset < 0 || endoff < 0)
 717  845                  return (EINVAL);
 718  846  
 719  847          /*
 720      -         * Check to make sure that the process will not exceed
 721      -         * its limit on file size.  It is okay to write up to
 722      -         * the limit, but not beyond.  Thus, the write which
 723      -         * reaches the limit will be short and the next write
 724      -         * will return an error.
 725      -         *
 726      -         * So if we're starting at or beyond the limit, EFBIG.
 727      -         * Otherwise, temporarily reduce resid to the amount
 728      -         * the falls after the limit.
      848 +         * Check to make sure that the process will not exceed its limit on
      849 +         * file size.  It is okay to write up to the limit, but not beyond.
      850 +         * Thus, the write which reaches the limit will be short and the next
      851 +         * write will return an error.
      852 +         * 
      853 +         * So if we're starting at or beyond the limit, EFBIG. Otherwise,
      854 +         * temporarily reduce resid to the amount the falls after the limit.
 729  855           */
 730  856          limit = uiop->uio_llimit;
 731  857          if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 732  858                  limit = MAXOFFSET_T;
 733  859          if (uiop->uio_loffset >= limit)
 734  860                  return (EFBIG);
 735  861          if (endoff > limit) {
 736      -                past_limit = (ssize_t)(endoff - limit);
      862 +                past_limit = (ssize_t) (endoff - limit);
 737  863                  uiop->uio_resid -= past_limit;
 738  864          } else
 739  865                  past_limit = 0;
 740  866  
 741      -        /* Timeout: longer for append. */
 742      -        timo = smb_timo_write;
 743      -        if (endoff > np->r_size)
 744      -                timo = smb_timo_append;
      867 +        /* Bypass the VM if vnode is non-cacheable. */
      868 +        if ((vp->v_flag & VNOCACHE) ||
      869 +            ((np->r_flags & RDIRECTIO) &&
      870 +             np->r_mapcnt == 0 &&
      871 +             !(vn_has_cached_data(vp)))) {
      872 +
      873 +                /* Timeout: longer for append. */
      874 +                timo = smb_timo_write;
      875 +                if (endoff > np->r_size)
      876 +                        timo = smb_timo_append;
 745  877  
 746      -        /* Shared lock for n_fid use in smb_rwuio */
 747      -        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 748      -                return (EINTR);
 749      -        smb_credinit(&scred, cr);
      878 +                /* Shared lock for n_fid use in smb_rwuio */
      879 +                if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
      880 +                        return (EINTR);
      881 +                smb_credinit(&scred, cr);
 750  882  
 751      -        /* After reconnect, n_fid is invalid */
 752      -        if (np->n_vcgenid != ssp->ss_vcgenid)
 753      -                error = ESTALE;
 754      -        else
 755      -                error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
 756      -                    uiop, &scred, timo);
      883 +                /* After reconnect, n_fid is invalid */
      884 +                if (np->n_vcgenid != ssp->ss_vcgenid)
      885 +                        error = ESTALE;
      886 +                else
      887 +                        error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
      888 +                                          uiop, &scred, timo);
 757  889  
 758      -        if (error == 0) {
 759      -                mutex_enter(&np->r_statelock);
 760      -                np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
 761      -                if (uiop->uio_loffset > (offset_t)np->r_size)
 762      -                        np->r_size = (len_t)uiop->uio_loffset;
 763      -                mutex_exit(&np->r_statelock);
 764      -                if (ioflag & (FSYNC|FDSYNC)) {
 765      -                        /* Don't error the I/O if this fails. */
 766      -                        (void) smbfs_smb_flush(np, &scred);
      890 +                if (error == 0) {
      891 +                        mutex_enter(&np->r_statelock);
      892 +                        np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
      893 +                        if (uiop->uio_loffset > (offset_t) np->r_size)
      894 +                                np->r_size = (len_t) uiop->uio_loffset;
      895 +                        mutex_exit(&np->r_statelock);
      896 +                        if (ioflag & (FSYNC | FDSYNC)) {
      897 +                                /* Don't error the I/O if this fails. */
      898 +                                (void) smbfs_smb_flush(np, &scred);
      899 +                        }
 767  900                  }
 768      -        }
      901 +                smb_credrele(&scred);
      902 +                smbfs_rw_exit(&np->r_lkserlock);
 769  903  
 770      -        smb_credrele(&scred);
 771      -        smbfs_rw_exit(&np->r_lkserlock);
      904 +        } else {
      905 +
      906 +                /* Do I/O through segmap. */
      907 +                size_t          bsize = vp->v_vfsp->vfs_bsize;
      908 +
      909 +                do {
      910 +                        blk = uiop->uio_loffset & MAXBMASK;
      911 +                        boff = uiop->uio_loffset & MAXBOFFSET;
      912 +                        blen = MIN(MAXBSIZE - boff, uiop->uio_resid);
      913 +
      914 +                        last_off = uiop->uio_loffset;
      915 +                        last_resid = uiop->uio_resid;
      916 +
      917 +                        uio_prefaultpages((ssize_t) blen, uiop);
      918 +
      919 +                        if (vpm_enable) {
      920 +
      921 +                                error = writenp(np, NULL, blen, uiop, 0);
      922 +
      923 +                        } else {
      924 +
      925 +                                if (segmap_kpm) {
      926 +                                        u_offset_t      poff = uiop->uio_loffset & PAGEOFFSET;
      927 +                                        size_t          plen = MIN(PAGESIZE - poff, uiop->uio_resid);
      928 +
      929 +                                        int             pagecreate;
      930 +
      931 +                                        mutex_enter(&np->r_statelock);
      932 +                                        pagecreate = (poff == 0) &&
      933 +                                                ((plen == PAGESIZE) ||
      934 +                                                 (uiop->uio_loffset + plen >= np->r_size));
      935 +                                        mutex_exit(&np->r_statelock);
      936 +
      937 +                                        base = segmap_getmapflt(segkmap, vp, blk + boff, plen, !pagecreate, S_WRITE);
      938 +                                        error = writenp(np, base + poff, blen, uiop, pagecreate);
      939 +
      940 +                                } else {
      941 +                                        base = segmap_getmapflt(segkmap, vp, blk + boff, blen, 0, S_READ);
      942 +                                        error = writenp(np, base + boff, blen, uiop, 0);
      943 +                                }
      944 +                        }
      945 +
      946 +                        if (!error) {
      947 +                                if (uiop->uio_loffset % bsize == 0) {
      948 +                                        flags = SM_WRITE | SM_DONTNEED;
      949 +                                } else {
      950 +                                        flags = 0;
      951 +                                }
      952 +
      953 +                                if (ioflag & (FSYNC | FDSYNC)) {
      954 +                                        flags &= ~SM_ASYNC;
      955 +                                        flags |= SM_WRITE;
      956 +                                }
      957 +                                if (vpm_enable) {
      958 +                                        error = vpm_sync_pages(vp, blk, blen, flags);
      959 +                                } else {
      960 +                                        error = segmap_release(segkmap, base, flags);
      961 +                                }
      962 +                        } else {
      963 +                                if (vpm_enable) {
      964 +                                        (void) vpm_sync_pages(vp, blk, blen, 0);
      965 +                                } else {
      966 +                                        (void) segmap_release(segkmap, base, 0);
      967 +                                }
      968 +                        }
      969 +                } while (!error && uiop->uio_resid > 0);
      970 +        }
 772  971  
 773  972          /* undo adjustment of resid */
 774      -        uiop->uio_resid += past_limit;
      973 +        if (error) {
      974 +                uiop->uio_resid = last_resid + past_limit;
      975 +                uiop->uio_loffset = last_off;
      976 +        } else {
      977 +                uiop->uio_resid += past_limit;
      978 +        }
 775  979  
 776  980          return (error);
 777  981  }
 778  982  
      983 +/* correspond to writerp() in nfs_client.c */
      984 +static int
      985 +writenp(smbnode_t * np, caddr_t base, int tcount, struct uio * uiop, int pgcreated)
      986 +{
      987 +        int             pagecreate;
      988 +        int             n;
      989 +        int             saved_n;
      990 +        caddr_t         saved_base;
      991 +        u_offset_t      offset;
      992 +        int             error;
      993 +        int             sm_error;
      994 +
      995 +        vnode_t        *vp = SMBTOV(np);
      996 +
      997 +        ASSERT(tcount <= MAXBSIZE && tcount <= uiop->uio_resid);
      998 +        ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
      999 +        if (!vpm_enable) {
     1000 +                ASSERT(((uintptr_t) base & MAXBOFFSET) + tcount <= MAXBSIZE);
     1001 +        }
     1002 +        /*
     1003 +         * Move bytes in at most PAGESIZE chunks. We must avoid spanning
     1004 +         * pages in uiomove() because page faults may cause the cache to be
     1005 +         * invalidated out from under us. The r_size is not updated until
     1006 +         * after the uiomove. If we push the last page of a file before
     1007 +         * r_size is correct, we will lose the data written past the current
     1008 +         * (and invalid) r_size.
     1009 +         */
     1010 +        do {
     1011 +                offset = uiop->uio_loffset;
     1012 +                pagecreate = 0;
     1013 +
     1014 +                /*
     1015 +                 * n is the number of bytes required to satisfy the request
     1016 +                 * or the number of bytes to fill out the page.
     1017 +                 */
     1018 +                n = (int) MIN((PAGESIZE - (offset & PAGEOFFSET)), tcount);
     1019 +
     1020 +                /*
     1021 +                 * Check to see if we can skip reading in the page and just
     1022 +                 * allocate the memory. We can do this if we are going to
     1023 +                 * rewrite the entire mapping or if we are going to write to
     1024 +                 * or beyond the current end of file from the beginning of
     1025 +                 * the mapping.
     1026 +                 * 
     1027 +                 * The read of r_size is now protected by r_statelock.
     1028 +                 */
     1029 +                mutex_enter(&np->r_statelock);
     1030 +                /*
     1031 +                 * When pgcreated is nonzero the caller has already done a
     1032 +                 * segmap_getmapflt with forcefault 0 and S_WRITE. With
     1033 +                 * segkpm this means we already have at least one page
     1034 +                 * created and mapped at base.
     1035 +                 */
     1036 +                pagecreate = pgcreated ||
     1037 +                        ((offset & PAGEOFFSET) == 0 &&
     1038 +                         (n == PAGESIZE || ((offset + n) >= np->r_size)));
     1039 +
     1040 +                mutex_exit(&np->r_statelock);
     1041 +
     1042 +                if (!vpm_enable && pagecreate) {
     1043 +                        /*
     1044 +                         * The last argument tells segmap_pagecreate() to
     1045 +                         * always lock the page, as opposed to sometimes
     1046 +                         * returning with the page locked. This way we avoid
     1047 +                         * a fault on the ensuing uiomove(), but also more
     1048 +                         * importantly (to fix bug 1094402) we can call
     1049 +                         * segmap_fault() to unlock the page in all cases. An
     1050 +                         * alternative would be to modify segmap_pagecreate()
     1051 +                         * to tell us when it is locking a page, but that's a
     1052 +                         * fairly major interface change.
     1053 +                         */
     1054 +                        if (pgcreated == 0)
     1055 +                                (void) segmap_pagecreate(segkmap, base,
     1056 +                                                         (uint_t) n, 1);
     1057 +                        saved_base = base;
     1058 +                        saved_n = n;
     1059 +                }
     1060 +                /*
     1061 +                 * The number of bytes of data in the last page can not be
     1062 +                 * accurately be determined while page is being uiomove'd to
     1063 +                 * and the size of the file being updated. Thus, inform
     1064 +                 * threads which need to know accurately how much data is in
     1065 +                 * the last page of the file. They will not do the i/o
     1066 +                 * immediately, but will arrange for the i/o to happen later
     1067 +                 * when this modify operation will have finished.
     1068 +                 */
     1069 +                ASSERT(!(np->r_flags & RMODINPROGRESS));
     1070 +                mutex_enter(&np->r_statelock);
     1071 +                np->r_flags |= RMODINPROGRESS;
     1072 +                np->r_modaddr = (offset & MAXBMASK);
     1073 +                mutex_exit(&np->r_statelock);
     1074 +
     1075 +                if (vpm_enable) {
     1076 +                        /*
     1077 +                         * Copy data. If new pages are created, part of the
     1078 +                         * page that is not written will be initizliazed with
     1079 +                         * zeros.
     1080 +                         */
     1081 +                        error = vpm_data_copy(vp, offset, n, uiop,
     1082 +                                              !pagecreate, NULL, 0, S_WRITE);
     1083 +                } else {
     1084 +                        error = uiomove(base, n, UIO_WRITE, uiop);
     1085 +                }
     1086 +
     1087 +                /*
     1088 +                 * r_size is the maximum number of bytes known to be in the
     1089 +                 * file. Make sure it is at least as high as the first
     1090 +                 * unwritten byte pointed to by uio_loffset.
     1091 +                 */
     1092 +                mutex_enter(&np->r_statelock);
     1093 +                if (np->r_size < uiop->uio_loffset)
     1094 +                        np->r_size = uiop->uio_loffset;
     1095 +                np->r_flags &= ~RMODINPROGRESS;
     1096 +                np->r_flags |= RDIRTY;
     1097 +                mutex_exit(&np->r_statelock);
     1098 +
     1099 +                /* n = # of bytes written */
     1100 +                n = (int) (uiop->uio_loffset - offset);
     1101 +
     1102 +                if (!vpm_enable) {
     1103 +                        base += n;
     1104 +                }
     1105 +                tcount -= n;
     1106 +                /*
     1107 +                 * If we created pages w/o initializing them completely, we
     1108 +                 * need to zero the part that wasn't set up. This happens on
     1109 +                 * a most EOF write cases and if we had some sort of error
     1110 +                 * during the uiomove.
     1111 +                 */
     1112 +                if (!vpm_enable && pagecreate) {
     1113 +                        if ((uiop->uio_loffset & PAGEOFFSET) || n == 0)
     1114 +                                (void) kzero(base, PAGESIZE - n);
     1115 +
     1116 +                        if (pgcreated) {
     1117 +                                /*
     1118 +                                 * Caller is responsible for this page, it
     1119 +                                 * was not created in this loop.
     1120 +                                 */
     1121 +                                pgcreated = 0;
     1122 +                        } else {
     1123 +                                /*
     1124 +                                 * For bug 1094402: segmap_pagecreate locks
     1125 +                                 * page. Unlock it. This also unlocks the
     1126 +                                 * pages allocated by page_create_va() in
     1127 +                                 * segmap_pagecreate().
     1128 +                                 */
     1129 +                                sm_error = segmap_fault(kas.a_hat, segkmap,
     1130 +                                                        saved_base, saved_n,
     1131 +                                                     F_SOFTUNLOCK, S_WRITE);
     1132 +                                if (error == 0)
     1133 +                                        error = sm_error;
     1134 +                        }
     1135 +                }
     1136 +        } while (tcount > 0 && error == 0);
     1137 +
     1138 +        return (error);
     1139 +}
 779 1140  
 780 1141  /* ARGSUSED */
 781 1142  static int
 782 1143  smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
 783 1144          cred_t *cr, int *rvalp, caller_context_t *ct)
 784 1145  {
 785 1146          int             error;
 786 1147          smbmntinfo_t    *smi;
 787 1148  
 788 1149          smi = VTOSMI(vp);
↓ open down ↓ 569 lines elided ↑ open up ↑
1358 1719                  /* Force last close. */
1359 1720                  np->n_dirrefs = 1;
1360 1721                  smbfs_rele_fid(np, &scred);
1361 1722                  break;
1362 1723  
1363 1724          case VREG:
1364 1725                  if (np->n_fidrefs == 0)
1365 1726                          break;
1366 1727                  SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1367 1728                      np->n_fidrefs, np->n_fid, np->n_rpath);
     1729 +                /*
     1730 +                 * Before otW close, make sure dirty pages written back.
     1731 +                 */
     1732 +                if (vn_has_cached_data(vp)) {
     1733 +                        /* smbfs_putapage() will acquire shared lock, so release
     1734 +                         * exclusive lock temporally.
     1735 +                         */
     1736 +                        smbfs_rw_exit(&np->r_lkserlock);
     1737 +
     1738 +                        (void) smbfs_putpage(vp, (offset_t) 0, 0, B_INVAL | B_ASYNC, cr, ct);
     1739 +
     1740 +                        /* acquire exclusive lock again. */
     1741 +                        (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
     1742 +                }
1368 1743                  /* Force last close. */
1369 1744                  np->n_fidrefs = 1;
1370 1745                  smbfs_rele_fid(np, &scred);
1371 1746                  break;
1372 1747  
1373 1748          default:
1374 1749                  SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1375 1750                  np->n_ovtype = VNON;
1376 1751                  break;
1377 1752          }
↓ open down ↓ 1725 lines elided ↑ open up ↑
3103 3478          caller_context_t *ct)
3104 3479  {
3105 3480          if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3106 3481                  return (EIO);
3107 3482  
3108 3483          if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3109 3484                  return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3110 3485          else
3111 3486                  return (ENOSYS);
3112 3487  }
     3488 +
     3489 +/* correspond to bp_mapin() in bp_map.c */
     3490 +static int 
     3491 +uio_page_mapin(uio_t * uiop, page_t * pp)
     3492 +{
     3493 +        u_offset_t      off;
     3494 +        size_t          size;
     3495 +        pgcnt_t         npages;
     3496 +        caddr_t         kaddr;
     3497 +        pfn_t           pfnum;
     3498 +
     3499 +        off = (uintptr_t) uiop->uio_loffset & PAGEOFFSET;
     3500 +        size = P2ROUNDUP(uiop->uio_resid + off, PAGESIZE);
     3501 +        npages = btop(size);
     3502 +
     3503 +        ASSERT(pp != NULL);
     3504 +
     3505 +        if (npages == 1 && kpm_enable) {
     3506 +                kaddr = hat_kpm_mapin(pp, NULL);
     3507 +                if (kaddr == NULL)
     3508 +                        return (EFAULT);
     3509 +
     3510 +                uiop->uio_iov->iov_base = kaddr + off;
     3511 +                uiop->uio_iov->iov_len = PAGESIZE - off;
     3512 +
     3513 +        } else {
     3514 +                kaddr = vmem_xalloc(heap_arena, size, PAGESIZE, 0, 0, NULL, NULL, VM_SLEEP);
     3515 +                if (kaddr == NULL)
     3516 +                        return (EFAULT);
     3517 +
     3518 +                uiop->uio_iov->iov_base = kaddr + off;
     3519 +                uiop->uio_iov->iov_len = size - off;
     3520 +
     3521 +                /* map pages into kaddr */
     3522 +                uint_t          attr = PROT_READ | PROT_WRITE | HAT_NOSYNC;
     3523 +                while (npages-- > 0) {
     3524 +                        pfnum = pp->p_pagenum;
     3525 +                        pp = pp->p_next;
     3526 +
     3527 +                        hat_devload(kas.a_hat, kaddr, PAGESIZE, pfnum, attr, HAT_LOAD_LOCK);
     3528 +                        kaddr += PAGESIZE;
     3529 +                }
     3530 +        }
     3531 +        return (0);
     3532 +}
     3533 +
     3534 +/* correspond to bp_mapout() in bp_map.c */
     3535 +static void 
     3536 +uio_page_mapout(uio_t * uiop, page_t * pp)
     3537 +{
     3538 +        u_offset_t      off;
     3539 +        size_t          size;
     3540 +        pgcnt_t         npages;
     3541 +        caddr_t         kaddr;
     3542 +
     3543 +        kaddr = uiop->uio_iov->iov_base;
     3544 +        off = (uintptr_t) kaddr & PAGEOFFSET;
     3545 +        size = P2ROUNDUP(uiop->uio_iov->iov_len + off, PAGESIZE);
     3546 +        npages = btop(size);
     3547 +
     3548 +        ASSERT(pp != NULL);
     3549 +
     3550 +        kaddr = (caddr_t) ((uintptr_t) kaddr & MMU_PAGEMASK);
     3551 +
     3552 +        if (npages == 1 && kpm_enable) {
     3553 +                hat_kpm_mapout(pp, NULL, kaddr);
     3554 +
     3555 +        } else {
     3556 +                hat_unload(kas.a_hat, (void *) kaddr, size,
     3557 +                           HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
     3558 +                vmem_free(heap_arena, (void *) kaddr, size);
     3559 +        }
     3560 +        uiop->uio_iov->iov_base = 0;
     3561 +        uiop->uio_iov->iov_len = 0;
     3562 +}
     3563 +
     3564 +static int 
     3565 +smbfs_map(vnode_t * vp, offset_t off, struct as * as, caddr_t * addrp,
     3566 +       size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t * cr,
     3567 +          caller_context_t * ct)
     3568 +{
     3569 +        smbnode_t      *np;
     3570 +        smbmntinfo_t   *smi;
     3571 +        struct vattr    va;
     3572 +        segvn_crargs_t  vn_a;
     3573 +        int             error;
     3574 +
     3575 +        np = VTOSMB(vp);
     3576 +        smi = VTOSMI(vp);
     3577 +
     3578 +        if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
     3579 +                return (EIO);
     3580 +
     3581 +        if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
     3582 +                return (EIO);
     3583 +
     3584 +        if (vp->v_flag & VNOMAP || vp->v_flag & VNOCACHE)
     3585 +                return (EAGAIN);
     3586 +
     3587 +        if (vp->v_type != VREG)
     3588 +                return (ENODEV);
     3589 +
     3590 +        va.va_mask = AT_ALL;
     3591 +        if (error = smbfsgetattr(vp, &va, cr))
     3592 +                return (error);
     3593 +
     3594 +        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
     3595 +                return (EINTR);
     3596 +
     3597 +        if (MANDLOCK(vp, va.va_mode)) {
     3598 +                error = EAGAIN;
     3599 +                goto out;
     3600 +        }
     3601 +        as_rangelock(as);
     3602 +        error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
     3603 +
     3604 +        if (error != 0) {
     3605 +                as_rangeunlock(as);
     3606 +                goto out;
     3607 +        }
     3608 +        vn_a.vp = vp;
     3609 +        vn_a.offset = off;
     3610 +        vn_a.type = flags & MAP_TYPE;
     3611 +        vn_a.prot = prot;
     3612 +        vn_a.maxprot = maxprot;
     3613 +        vn_a.flags = flags & ~MAP_TYPE;
     3614 +        vn_a.cred = cr;
     3615 +        vn_a.amp = NULL;
     3616 +        vn_a.szc = 0;
     3617 +        vn_a.lgrp_mem_policy_flags = 0;
     3618 +
     3619 +        error = as_map(as, *addrp, len, segvn_create, &vn_a);
     3620 +
     3621 +        as_rangeunlock(as);
     3622 +
     3623 +out:
     3624 +        smbfs_rw_exit(&np->r_lkserlock);
     3625 +
     3626 +        return (error);
     3627 +}
     3628 +
     3629 +static int 
     3630 +smbfs_addmap(vnode_t * vp, offset_t off, struct as * as, caddr_t addr,
     3631 +       size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t * cr,
     3632 +             caller_context_t * ct)
     3633 +{
     3634 +        atomic_add_long((ulong_t *) & VTOSMB(vp)->r_mapcnt, btopr(len));
     3635 +        return (0);
     3636 +}
     3637 +
     3638 +static int 
     3639 +smbfs_delmap(vnode_t * vp, offset_t off, struct as * as, caddr_t addr,
     3640 +         size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t * cr,
     3641 +             caller_context_t * ct)
     3642 +{
     3643 +
     3644 +        smbnode_t      *np;
     3645 +
     3646 +        atomic_add_long((ulong_t *) & VTOSMB(vp)->r_mapcnt, -btopr(len));
     3647 +
     3648 +        /*
     3649 +         * mark RDIRTY here, will be used to check if a file is dirty when
     3650 +         * unmount smbfs
     3651 +         */
     3652 +        if (vn_has_cached_data(vp) && !vn_is_readonly(vp) && (maxprot & PROT_WRITE)
     3653 +            && (flags == MAP_SHARED)) {
     3654 +                np = VTOSMB(vp);
     3655 +                mutex_enter(&np->r_statelock);
     3656 +                np->r_flags |= RDIRTY;
     3657 +                mutex_exit(&np->r_statelock);
     3658 +        }
     3659 +        return (0);
     3660 +}
     3661 +
     3662 +static int 
     3663 +smbfs_putpage(vnode_t * vp, offset_t off, size_t len, int flags,
     3664 +              cred_t * cr, caller_context_t * ct)
     3665 +{
     3666 +
     3667 +        smbnode_t      *np;
     3668 +        size_t          io_len;
     3669 +        u_offset_t      io_off;
     3670 +        u_offset_t      eoff;
     3671 +        int             error = 0;
     3672 +        page_t         *pp;
     3673 +        int             rdirty;
     3674 +
     3675 +        np = VTOSMB(vp);
     3676 +
     3677 +        if (len == 0) {
     3678 +
     3679 +                /* will flush the whole file, so clear RDIRTY */
     3680 +                if (off == (u_offset_t) 0 && (np->r_flags & RDIRTY)) {
     3681 +                        mutex_enter(&np->r_statelock);
     3682 +                        rdirty = np->r_flags & RDIRTY;
     3683 +                        np->r_flags &= ~RDIRTY;
     3684 +                        mutex_exit(&np->r_statelock);
     3685 +                } else
     3686 +                        rdirty = 0;
     3687 +
     3688 +                error = pvn_vplist_dirty(vp, off, smbfs_putapage, flags, cr);
     3689 +
     3690 +                /*
     3691 +                 * if failed and the vnode was dirty before and we aren't
     3692 +                 * forcibly invalidating pages, then mark RDIRTY again.
     3693 +                 */
     3694 +                if (error && rdirty &&
     3695 +                    (flags & (B_INVAL | B_FORCE)) != (B_INVAL | B_FORCE)) {
     3696 +                        mutex_enter(&np->r_statelock);
     3697 +                        np->r_flags |= RDIRTY;
     3698 +                        mutex_exit(&np->r_statelock);
     3699 +                }
     3700 +        } else {
     3701 +
     3702 +                eoff = off + len;
     3703 +
     3704 +                mutex_enter(&np->r_statelock);
     3705 +                if (eoff > np->r_size)
     3706 +                        eoff = np->r_size;
     3707 +                mutex_exit(&np->r_statelock);
     3708 +
     3709 +                for (io_off = off; io_off < eoff; io_off += io_len) {
     3710 +                        if ((flags & B_INVAL) || (flags & B_ASYNC) == 0) {
     3711 +                                pp = page_lookup(vp, io_off,
     3712 +                                                 (flags & (B_INVAL | B_FREE) ? SE_EXCL : SE_SHARED));
     3713 +                        } else {
     3714 +                                pp = page_lookup_nowait(vp, io_off,
     3715 +                                    (flags & B_FREE) ? SE_EXCL : SE_SHARED);
     3716 +                        }
     3717 +
     3718 +                        if (pp == NULL || !pvn_getdirty(pp, flags))
     3719 +                                io_len = PAGESIZE;
     3720 +                        else {
     3721 +                                error = smbfs_putapage(vp, pp, &io_off, &io_len, flags, cr);
     3722 +                        }
     3723 +                }
     3724 +
     3725 +        }
     3726 +
     3727 +        return (error);
     3728 +}
     3729 +
     3730 +static int 
     3731 +smbfs_putapage(vnode_t * vp, page_t * pp, u_offset_t * offp, size_t * lenp,
     3732 +               int flags, cred_t * cr)
     3733 +{
     3734 +
     3735 +        struct smb_cred scred;
     3736 +        smbnode_t      *np;
     3737 +        smbmntinfo_t   *smi;
     3738 +        smb_share_t    *ssp;
     3739 +        uio_t           uio;
     3740 +        iovec_t         uiov, uiov_bak;
     3741 +
     3742 +        size_t          io_len;
     3743 +        u_offset_t      io_off;
     3744 +        size_t          limit;
     3745 +        size_t          bsize;
     3746 +        size_t          blksize;
     3747 +        u_offset_t      blkoff;
     3748 +        int             error;
     3749 +
     3750 +        np = VTOSMB(vp);
     3751 +        smi = VTOSMI(vp);
     3752 +        ssp = smi->smi_share;
     3753 +
     3754 +        /* do block io, get a kluster of dirty pages in a block. */
     3755 +        bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
     3756 +        blkoff = pp->p_offset / bsize;
     3757 +        blkoff *= bsize;
     3758 +        blksize = roundup(bsize, PAGESIZE);
     3759 +
     3760 +        pp = pvn_write_kluster(vp, pp, &io_off, &io_len, blkoff, blksize, flags);
     3761 +
     3762 +        ASSERT(pp->p_offset >= blkoff);
     3763 +
     3764 +        if (io_off + io_len > blkoff + blksize) {
     3765 +                ASSERT((io_off + io_len) - (blkoff + blksize) < PAGESIZE);
     3766 +        }
     3767 +
     3768 +        /* Don't allow put pages beyond EOF */
     3769 +        mutex_enter(&np->r_statelock);
     3770 +        limit=MIN(np->r_size, blkoff + blksize);
     3771 +        mutex_exit(&np->r_statelock);
     3772 +
     3773 +        if (io_off >= limit) {
     3774 +                error = 0;
     3775 +                goto out;
     3776 +        } else if (io_off + io_len > limit) {
     3777 +                int             npages = btopr(limit - io_off);
     3778 +                page_t         *trunc;
     3779 +                page_list_break(&pp, &trunc, npages);
     3780 +                if (trunc)
     3781 +                        pvn_write_done(trunc, flags);
     3782 +                io_len = limit - io_off;
     3783 +        }
     3784 +
     3785 +        /*
     3786 +         * Taken from NFS4. The RMODINPROGRESS flag makes sure that
     3787 +         * smbfs_putapage() sees a consistent value of r_size. RMODINPROGRESS
     3788 +         * is set in writenp(). When RMODINPROGRESS is set it indicates that
     3789 +         * a uiomove() is in progress and the r_size has not been made
     3790 +         * consistent with the new size of the file. When the uiomove()
     3791 +         * completes the r_size is updated and the RMODINPROGRESS flag is
     3792 +         * cleared.
     3793 +         * 
     3794 +         * The RMODINPROGRESS flag makes sure that smbfs_putapage() sees a
     3795 +         * consistent value of r_size. Without this handshaking, it is
     3796 +         * possible that smbfs_putapage() picks  up the old value of r_size
     3797 +         * before the uiomove() in writenp() completes. This will result in
     3798 +         * the write through smbfs_putapage() being dropped.
     3799 +         * 
     3800 +         * More precisely, there is a window between the time the uiomove()
     3801 +         * completes and the time the r_size is updated. If a VOP_PUTPAGE()
     3802 +         * operation intervenes in this window, the page will be picked up,
     3803 +         * because it is dirty (it will be unlocked, unless it was
     3804 +         * pagecreate'd). When the page is picked up as dirty, the dirty bit
     3805 +         * is reset (pvn_getdirty()). In smbfs_putapage(), r_size is checked.
     3806 +         * This will still be the old size. Therefore the page will not be
     3807 +         * written out. When segmap_release() calls VOP_PUTPAGE(), the page
     3808 +         * will be found to be clean and the write will be dropped.
     3809 +         */
     3810 +        if (np->r_flags & RMODINPROGRESS) {
     3811 +
     3812 +                mutex_enter(&np->r_statelock);
     3813 +                if ((np->r_flags & RMODINPROGRESS) &&
     3814 +                    np->r_modaddr + MAXBSIZE > io_off &&
     3815 +                    np->r_modaddr < io_off + io_len) {
     3816 +                        page_t         *plist;
     3817 +                        /*
     3818 +                         * A write is in progress for this region of the
     3819 +                         * file. If we did not detect RMODINPROGRESS here,
     3820 +                         * the data beyond the file size won't be write out.
     3821 +                         * We end up losing data. So we decide to set the
     3822 +                         * modified bit on each page in the page list and
     3823 +                         * mark the smbnode with RDIRTY. This write will be
     3824 +                         * restarted at some later time.
     3825 +                         */
     3826 +                        plist = pp;
     3827 +                        while (plist != NULL) {
     3828 +                                pp = plist;
     3829 +                                page_sub(&plist, pp);
     3830 +                                hat_setmod(pp);
     3831 +                                page_io_unlock(pp);
     3832 +                                page_unlock(pp);
     3833 +                        }
     3834 +                        np->r_flags |= RDIRTY;
     3835 +                        mutex_exit(&np->r_statelock);
     3836 +                        if (offp)
     3837 +                                *offp = io_off;
     3838 +                        if (lenp)
     3839 +                                *lenp = io_len;
     3840 +                        return (0);
     3841 +                }
     3842 +                mutex_exit(&np->r_statelock);
     3843 +        }
     3844 +
     3845 +        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
     3846 +                return (EINTR);
     3847 +        smb_credinit(&scred, cr);
     3848 +
     3849 +        if (np->n_vcgenid != ssp->ss_vcgenid)
     3850 +                error = ESTALE;
     3851 +        else {
     3852 +                /* just use uio instead of buf, since smb_rwuio need uio. */
     3853 +                uiov.iov_base = 0;
     3854 +                uiov.iov_len = 0;
     3855 +                uio.uio_iov = &uiov;
     3856 +                uio.uio_iovcnt = 1;
     3857 +                uio.uio_loffset = io_off;
     3858 +                uio.uio_resid = io_len;
     3859 +                uio.uio_segflg = UIO_SYSSPACE;
     3860 +                uio.uio_llimit = MAXOFFSET_T;
     3861 +                /* map pages into kernel address space, and setup uio. */
     3862 +                error = uio_page_mapin(&uio, pp);
     3863 +                if (error == 0) {
     3864 +                        uiov_bak.iov_base = uiov.iov_base;
     3865 +                        uiov_bak.iov_len = uiov.iov_len;
     3866 +                        error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, &uio, &scred, smb_timo_write);
     3867 +                        if (error == 0) {
     3868 +                                mutex_enter(&np->r_statelock);
     3869 +                                np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
     3870 +                                mutex_exit(&np->r_statelock);
     3871 +                                (void) smbfs_smb_flush(np, &scred);
     3872 +                        }
     3873 +                        /* unmap pages from kernel address space. */
     3874 +                        uio.uio_iov = &uiov_bak;
     3875 +                        uio_page_mapout(&uio, pp);
     3876 +                }
     3877 +        }
     3878 +
     3879 +        smb_credrele(&scred);
     3880 +        smbfs_rw_exit(&np->r_lkserlock);
     3881 +
     3882 +out:
     3883 +        pvn_write_done(pp, ((error) ? B_ERROR : 0) | B_WRITE | flags);
     3884 +
     3885 +        if (offp)
     3886 +                *offp = io_off;
     3887 +        if (lenp)
     3888 +                *lenp = io_len;
     3889 +
     3890 +        return (error);
     3891 +}
     3892 +
     3893 +static int 
     3894 +smbfs_getpage(vnode_t * vp, offset_t off, size_t len, uint_t * protp,
     3895 +              page_t * pl[], size_t plsz, struct seg * seg, caddr_t addr,
     3896 +              enum seg_rw rw, cred_t * cr, caller_context_t * ct)
     3897 +{
     3898 +
     3899 +        smbnode_t      *np;
     3900 +        int             error;
     3901 +
     3902 +        /* these pages have all protections. */
     3903 +        if (protp)
     3904 +                *protp = PROT_ALL;
     3905 +
     3906 +        np = VTOSMB(vp);
     3907 +
     3908 +        /* Don't allow get pages beyond EOF, unless it's segkmap. */
     3909 +        mutex_enter(&np->r_statelock);
     3910 +        if (off + len > np->r_size + PAGESIZE && seg != segkmap){
     3911 +                mutex_exit(&np->r_statelock);
     3912 +                return (EFAULT);
     3913 +        }
     3914 +        mutex_exit(&np->r_statelock);
     3915 +
     3916 +        if (len <= PAGESIZE) {
     3917 +                error = smbfs_getapage(vp, off, len, protp, pl, plsz, seg, addr, rw,
     3918 +                                       cr);
     3919 +        } else {
     3920 +                error = pvn_getpages(smbfs_getapage, vp, off, len, protp, pl, plsz, seg,
     3921 +                                     addr, rw, cr);
     3922 +        }
     3923 +
     3924 +        return (error);
     3925 +}
     3926 +
     3927 +static int 
     3928 +smbfs_getapage(vnode_t * vp, u_offset_t off, size_t len,
     3929 + uint_t * protp, page_t * pl[], size_t plsz, struct seg * seg, caddr_t addr,
     3930 +               enum seg_rw rw, cred_t * cr)
     3931 +{
     3932 +
     3933 +        smbnode_t      *np;
     3934 +        smbmntinfo_t   *smi;
     3935 +        smb_share_t    *ssp;
     3936 +        smb_cred_t      scred;
     3937 +
     3938 +        page_t         *pp;
     3939 +        uio_t           uio;
     3940 +        iovec_t         uiov, uiov_bak;
     3941 +
     3942 +        u_offset_t      blkoff;
     3943 +        size_t          bsize;
     3944 +        size_t          blksize;
     3945 +
     3946 +        u_offset_t      io_off;
     3947 +        size_t          io_len;
     3948 +        size_t          pages_len;
     3949 +
     3950 +        int             error = 0;
     3951 +
     3952 +        np = VTOSMB(vp);
     3953 +        smi = VTOSMI(vp);
     3954 +        ssp = smi->smi_share;
     3955 +
     3956 +        /* if pl is null,it's meaningless */
     3957 +        if (pl == NULL)
     3958 +                return (EFAULT);
     3959 +
     3960 +again:
     3961 +        if (page_exists(vp, off) == NULL) {
     3962 +                if (rw == S_CREATE) {
     3963 +                        /* just return a empty page if asked to create. */
     3964 +                        if ((pp = page_create_va(vp, off, PAGESIZE, PG_WAIT | PG_EXCL, seg, addr)) == NULL)
     3965 +                                goto again;
     3966 +                        pages_len = PAGESIZE;
     3967 +                } else {
     3968 +
     3969 +                        /*
     3970 +                         * do block io, get a kluster of non-exist pages in a
     3971 +                         * block.
     3972 +                         */
     3973 +                        bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
     3974 +                        blkoff = off / bsize;
     3975 +                        blkoff *= bsize;
     3976 +                        blksize = roundup(bsize, PAGESIZE);
     3977 +
     3978 +                        pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len, blkoff, blksize, 0);
     3979 +
     3980 +                        if (pp == NULL)
     3981 +                                goto again;
     3982 +
     3983 +                        pages_len = io_len;
     3984 +
     3985 +                        /* Don't need to get pages from server if it's segkmap 
     3986 +                         * that reads beyond EOF. */
     3987 +                        mutex_enter(&np->r_statelock);
     3988 +                        if (io_off >= np->r_size && seg == segkmap) {
     3989 +                                mutex_exit(&np->r_statelock);
     3990 +                                error = 0;
     3991 +                                goto out;
     3992 +                        } else if (io_off + io_len > np->r_size) {
     3993 +                                int             npages = btopr(np->r_size - io_off);
     3994 +                                page_t         *trunc;
     3995 +
     3996 +                                page_list_break(&pp, &trunc, npages);
     3997 +                                if (trunc)
     3998 +                                        pvn_read_done(trunc, 0);
     3999 +                                io_len = np->r_size - io_off;
     4000 +                        }
     4001 +                        mutex_exit(&np->r_statelock);
     4002 +
     4003 +                        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
     4004 +                                return EINTR;
     4005 +                        smb_credinit(&scred, cr);
     4006 +
     4007 +                        /*
     4008 +                         * just use uio instead of buf, since smb_rwuio need
     4009 +                         * uio.
     4010 +                         */
     4011 +                        uiov.iov_base = 0;
     4012 +                        uiov.iov_len = 0;
     4013 +                        uio.uio_iov = &uiov;
     4014 +                        uio.uio_iovcnt = 1;
     4015 +                        uio.uio_loffset = io_off;
     4016 +                        uio.uio_resid = io_len;
     4017 +                        uio.uio_segflg = UIO_SYSSPACE;
     4018 +                        uio.uio_llimit = MAXOFFSET_T;
     4019 +
     4020 +                        /*
     4021 +                         * map pages into kernel address space, and setup
     4022 +                         * uio.
     4023 +                         */
     4024 +                        error = uio_page_mapin(&uio, pp);
     4025 +                        if (error == 0) {
     4026 +                                uiov_bak.iov_base = uiov.iov_base;
     4027 +                                uiov_bak.iov_len = uiov.iov_len;
     4028 +                                error = smb_rwuio(ssp, np->n_fid, UIO_READ, &uio, &scred, smb_timo_read);
     4029 +                                /* unmap pages from kernel address space. */
     4030 +                                uio.uio_iov = &uiov_bak;
     4031 +                                uio_page_mapout(&uio, pp);
     4032 +                        }
     4033 +                        smb_credrele(&scred);
     4034 +                        smbfs_rw_exit(&np->r_lkserlock);
     4035 +                }
     4036 +        } else {
     4037 +                se_t            se = rw == S_CREATE ? SE_EXCL : SE_SHARED;
     4038 +                if ((pp = page_lookup(vp, off, se)) == NULL) {
     4039 +                        goto again;
     4040 +                }
     4041 +        }
     4042 +
     4043 +out:
     4044 +        if (pp) {
     4045 +                if (error) {
     4046 +                        pvn_read_done(pp, B_ERROR);
     4047 +                } else {
     4048 +                        /* init page list, unlock pages. */
     4049 +                        pvn_plist_init(pp, pl, plsz, off, pages_len, rw);
     4050 +                }
     4051 +        }
     4052 +        return (error);
     4053 +}
     4054 +
     4055 +/* correspond to nfs_invalidate_pages() in nfs_client.c */
     4056 +void 
     4057 +smbfs_invalidate_pages(vnode_t * vp, u_offset_t off, cred_t * cr)
     4058 +{
     4059 +
     4060 +        smbnode_t      *np;
     4061 +
     4062 +        np = VTOSMB(vp);
     4063 +        /* will flush the whole file, so clear RDIRTY */
     4064 +        if (off == (u_offset_t) 0 && (np->r_flags & RDIRTY)) {
     4065 +                mutex_enter(&np->r_statelock);
     4066 +                np->r_flags &= ~RDIRTY;
     4067 +                mutex_exit(&np->r_statelock);
     4068 +        }
     4069 +        (void) pvn_vplist_dirty(vp, off, smbfs_putapage, B_INVAL | B_TRUNC, cr);
     4070 +}
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX