Print this page
*** NO COMMENTS ***


  34 
  35 /*
  36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37  */
  38 
  39 #include <sys/systm.h>
  40 #include <sys/cred.h>
  41 #include <sys/vnode.h>
  42 #include <sys/vfs.h>
  43 #include <sys/filio.h>
  44 #include <sys/uio.h>
  45 #include <sys/dirent.h>
  46 #include <sys/errno.h>
  47 #include <sys/sunddi.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/kmem.h>
  50 #include <sys/cmn_err.h>
  51 #include <sys/vfs_opreg.h>
  52 #include <sys/policy.h>
  53 












  54 #include <netsmb/smb_osdep.h>
  55 #include <netsmb/smb.h>
  56 #include <netsmb/smb_conn.h>
  57 #include <netsmb/smb_subr.h>
  58 
  59 #include <smbfs/smbfs.h>
  60 #include <smbfs/smbfs_node.h>
  61 #include <smbfs/smbfs_subr.h>
  62 
  63 #include <sys/fs/smbfs_ioctl.h>
  64 #include <fs/fs_subr.h>
  65 
  66 /*
  67  * We assign directory offsets like the NFS client, where the
  68  * offset increments by _one_ after each directory entry.
  69  * Further, the entries "." and ".." are always at offsets
  70  * zero and one (respectively) and the "real" entries from
  71  * the server appear at offsets starting with two.  This
  72  * macro is used to initialize the n_dirofs field after
  73  * setting n_dirseq with a _findopen call.


 158 static int      smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
 159                         caller_context_t *, int);
 160 static int      smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
 161                         caller_context_t *, int);
 162 static int      smbfs_rwlock(vnode_t *, int, caller_context_t *);
 163 static void     smbfs_rwunlock(vnode_t *, int, caller_context_t *);
 164 static int      smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
 165 static int      smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
 166                         struct flk_callback *, cred_t *, caller_context_t *);
 167 static int      smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
 168                         cred_t *, caller_context_t *);
 169 static int      smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 170                         caller_context_t *);
 171 static int      smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 172                         caller_context_t *);
 173 static int      smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 174                         caller_context_t *);
 175 static int      smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 176                         caller_context_t *);
 177 
































 178 /* Dummy function to use until correct function is ported in */
 179 int noop_vnodeop() {
 180         return (0);
 181 }
 182 
 183 struct vnodeops *smbfs_vnodeops = NULL;
 184 
 185 /*
 186  * Most unimplemented ops will return ENOSYS because of fs_nosys().
 187  * The only ops where that won't work are ACCESS (due to open(2)
 188  * failures) and ... (anything else left?)
 189  */
 190 const fs_operation_def_t smbfs_vnodeops_template[] = {
 191         { VOPNAME_OPEN,         { .vop_open = smbfs_open } },
 192         { VOPNAME_CLOSE,        { .vop_close = smbfs_close } },
 193         { VOPNAME_READ,         { .vop_read = smbfs_read } },
 194         { VOPNAME_WRITE,        { .vop_write = smbfs_write } },
 195         { VOPNAME_IOCTL,        { .vop_ioctl = smbfs_ioctl } },
 196         { VOPNAME_GETATTR,      { .vop_getattr = smbfs_getattr } },
 197         { VOPNAME_SETATTR,      { .vop_setattr = smbfs_setattr } },
 198         { VOPNAME_ACCESS,       { .vop_access = smbfs_access } },
 199         { VOPNAME_LOOKUP,       { .vop_lookup = smbfs_lookup } },
 200         { VOPNAME_CREATE,       { .vop_create = smbfs_create } },
 201         { VOPNAME_REMOVE,       { .vop_remove = smbfs_remove } },
 202         { VOPNAME_LINK,         { .error = fs_nosys } }, /* smbfs_link, */
 203         { VOPNAME_RENAME,       { .vop_rename = smbfs_rename } },
 204         { VOPNAME_MKDIR,        { .vop_mkdir = smbfs_mkdir } },
 205         { VOPNAME_RMDIR,        { .vop_rmdir = smbfs_rmdir } },
 206         { VOPNAME_READDIR,      { .vop_readdir = smbfs_readdir } },
 207         { VOPNAME_SYMLINK,      { .error = fs_nosys } }, /* smbfs_symlink, */
 208         { VOPNAME_READLINK,     { .error = fs_nosys } }, /* smbfs_readlink, */
 209         { VOPNAME_FSYNC,        { .vop_fsync = smbfs_fsync } },
 210         { VOPNAME_INACTIVE,     { .vop_inactive = smbfs_inactive } },
 211         { VOPNAME_FID,          { .error = fs_nosys } }, /* smbfs_fid, */
 212         { VOPNAME_RWLOCK,       { .vop_rwlock = smbfs_rwlock } },
 213         { VOPNAME_RWUNLOCK,     { .vop_rwunlock = smbfs_rwunlock } },
 214         { VOPNAME_SEEK,         { .vop_seek = smbfs_seek } },
 215         { VOPNAME_FRLOCK,       { .vop_frlock = smbfs_frlock } },
 216         { VOPNAME_SPACE,        { .vop_space = smbfs_space } },
 217         { 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, */

 223         { VOPNAME_DUMP,         { .error = fs_nosys } }, /* smbfs_dump, */
 224         { VOPNAME_PATHCONF,     { .vop_pathconf = smbfs_pathconf } },
 225         { VOPNAME_PAGEIO,       { .error = fs_nosys } }, /* smbfs_pageio, */
 226         { VOPNAME_SETSECATTR,   { .vop_setsecattr = smbfs_setsecattr } },
 227         { VOPNAME_GETSECATTR,   { .vop_getsecattr = smbfs_getsecattr } },
 228         { VOPNAME_SHRLOCK,      { .vop_shrlock = smbfs_shrlock } },
 229         { NULL, NULL }
 230 };
 231 
 232 /*
 233  * XXX
 234  * When new and relevant functionality is enabled, we should be
 235  * calling vfs_set_feature() to inform callers that pieces of
 236  * functionality are available, per PSARC 2007/227.
 237  */
 238 /* ARGSUSED */
 239 static int
 240 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 241 {
 242         smbnode_t       *np;


 469         }
 470 
 471         /*
 472          * This (passed in) count is the ref. count from the
 473          * user's file_t before the closef call (fio.c).
 474          * We only care when the reference goes away.
 475          */
 476         if (count > 1)
 477                 return (0);
 478 
 479         /*
 480          * Decrement the reference count for the FID
 481          * and possibly do the OtW close.
 482          *
 483          * Exclusive lock for modifying n_fid stuff.
 484          * Don't want this one ever interruptible.
 485          */
 486         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
 487         smb_credinit(&scred, cr);
 488 











 489         smbfs_rele_fid(np, &scred);

















 490 
 491         smb_credrele(&scred);
 492         smbfs_rw_exit(&np->r_lkserlock);
 493 
 494         return (0);
 495 }
 496 
 497 /*
 498  * Helper for smbfs_close.  Decrement the reference count
 499  * for an SMB-level file or directory ID, and when the last
 500  * reference for the fid goes away, do the OtW close.
 501  * Also called in smbfs_inactive (defensive cleanup).
 502  */
 503 static void
 504 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
 505 {
 506         smb_share_t     *ssp;
 507         cred_t          *oldcr;
 508         struct smbfs_fctx *fctx;
 509         int             error;


 558         }
 559 
 560         /* Allow next open to use any v_type. */
 561         np->n_ovtype = VNON;
 562 
 563         /*
 564          * Other "last close" stuff.
 565          */
 566         mutex_enter(&np->r_statelock);
 567         if (np->n_flag & NATTRCHANGED)
 568                 smbfs_attrcache_rm_locked(np);
 569         oldcr = np->r_cred;
 570         np->r_cred = NULL;
 571         mutex_exit(&np->r_statelock);
 572         if (oldcr != NULL)
 573                 crfree(oldcr);
 574 }
 575 
 576 /* ARGSUSED */
 577 static int
 578 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 579         caller_context_t *ct)
 580 {
 581         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;
 589 






 590         np = VTOSMB(vp);
 591         smi = VTOSMI(vp);
 592         ssp = smi->smi_share;
 593 
 594         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 595                 return (EIO);
 596 
 597         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 598                 return (EIO);
 599 
 600         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
 601 
 602         if (vp->v_type != VREG)
 603                 return (EISDIR);
 604 
 605         if (uiop->uio_resid == 0)
 606                 return (0);
 607 
 608         /*
 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.
 612          */
 613         endoff = uiop->uio_loffset + uiop->uio_resid;
 614         if (uiop->uio_loffset < 0 || endoff < 0)
 615                 return (EINVAL);
 616 
 617         /* get vnode attributes from server */
 618         va.va_mask = AT_SIZE | AT_MTIME;
 619         if (error = smbfsgetattr(vp, &va, cr))
 620                 return (error);
 621 
 622         /* Update mtime with mtime from server here? */
 623 
 624         /* if offset is beyond EOF, read nothing */
 625         if (uiop->uio_loffset >= va.va_size)
 626                 return (0);
 627 
 628         /*
 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.
 632          */
 633         if (endoff > va.va_size) {
 634                 past_eof = (ssize_t)(endoff - va.va_size);
 635                 uiop->uio_resid -= past_eof;
 636         } else
 637                 past_eof = 0;
 638 






 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);
 643 
 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);
 650 
 651         smb_credrele(&scred);
 652         smbfs_rw_exit(&np->r_lkserlock);
 653 






































 654         /* undo adjustment of resid */
 655         uiop->uio_resid += past_eof;
 656 
 657         return (error);
 658 }
 659 
 660 
 661 /* ARGSUSED */
 662 static int
 663 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 664         caller_context_t *ct)
 665 {
 666         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;
 674 









 675         np = VTOSMB(vp);
 676         smi = VTOSMI(vp);
 677         ssp = smi->smi_share;
 678 
 679         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 680                 return (EIO);
 681 
 682         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 683                 return (EIO);
 684 
 685         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
 686 
 687         if (vp->v_type != VREG)
 688                 return (EISDIR);
 689 
 690         if (uiop->uio_resid == 0)
 691                 return (0);
 692 
 693         /*
 694          * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
 695          */
 696         if (ioflag & (FAPPEND | FSYNC)) {
 697                 if (np->n_flag & NMODIFIED) {
 698                         smbfs_attrcache_remove(np);
 699                         /* XXX: smbfs_vinvalbuf? */
 700                 }
 701         }
 702         if (ioflag & FAPPEND) {
 703                 /*
 704                  * File size can be changed by another client
 705                  */
 706                 va.va_mask = AT_SIZE;
 707                 if (error = smbfsgetattr(vp, &va, cr))
 708                         return (error);
 709                 uiop->uio_loffset = va.va_size;
 710         }
 711 
 712         /*
 713          * Like NFS3, just check for 63-bit overflow.
 714          */
 715         endoff = uiop->uio_loffset + uiop->uio_resid;
 716         if (uiop->uio_loffset < 0 || endoff < 0)
 717                 return (EINVAL);
 718 
 719         /*
 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.
 729          */
 730         limit = uiop->uio_llimit;
 731         if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 732                 limit = MAXOFFSET_T;
 733         if (uiop->uio_loffset >= limit)
 734                 return (EFBIG);
 735         if (endoff > limit) {
 736                 past_limit = (ssize_t)(endoff - limit);
 737                 uiop->uio_resid -= past_limit;
 738         } else
 739                 past_limit = 0;
 740 






 741         /* Timeout: longer for append. */
 742         timo = smb_timo_write;
 743         if (endoff > np->r_size)
 744                 timo = smb_timo_append;
 745 
 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);
 750 
 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);
 757 
 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);
 767                 }
 768         }
 769 
 770         smb_credrele(&scred);
 771         smbfs_rw_exit(&np->r_lkserlock);
 772 




































































 773         /* undo adjustment of resid */




 774         uiop->uio_resid += past_limit;

 775 
 776         return (error);
 777 }
 778 





























































































































































 779 
 780 /* ARGSUSED */
 781 static int
 782 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
 783         cred_t *cr, int *rvalp, caller_context_t *ct)
 784 {
 785         int             error;
 786         smbmntinfo_t    *smi;
 787 
 788         smi = VTOSMI(vp);
 789 
 790         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 791                 return (EIO);
 792 
 793         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 794                 return (EIO);
 795 
 796         switch (cmd) {
 797                 /* First three from ZFS. XXX - need these? */
 798 


1348         switch (np->n_ovtype) {
1349         case VNON:
1350                 /* not open (OK) */
1351                 break;
1352 
1353         case VDIR:
1354                 if (np->n_dirrefs == 0)
1355                         break;
1356                 SMBVDEBUG("open dir: refs %d path %s\n",
1357                     np->n_dirrefs, np->n_rpath);
1358                 /* Force last close. */
1359                 np->n_dirrefs = 1;
1360                 smbfs_rele_fid(np, &scred);
1361                 break;
1362 
1363         case VREG:
1364                 if (np->n_fidrefs == 0)
1365                         break;
1366                 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1367                     np->n_fidrefs, np->n_fid, np->n_rpath);














1368                 /* Force last close. */
1369                 np->n_fidrefs = 1;
1370                 smbfs_rele_fid(np, &scred);
1371                 break;
1372 
1373         default:
1374                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1375                 np->n_ovtype = VNON;
1376                 break;
1377         }
1378 
1379         smb_credrele(&scred);
1380         smbfs_rw_exit(&np->r_lkserlock);
1381 
1382         smbfs_addfree(np);
1383 }
1384 
1385 /*
1386  * Remote file system operations having to do with directory manipulation.
1387  */


3093         return (error);
3094 }
3095 
3096 
3097 /*
3098  * XXX
3099  * This op should eventually support PSARC 2007/268.
3100  */
3101 static int
3102 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3103         caller_context_t *ct)
3104 {
3105         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3106                 return (EIO);
3107 
3108         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3109                 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3110         else
3111                 return (ENOSYS);
3112 }









































































































































































































































































































































































































































































































































































































  34 
  35 /*
  36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37  */
  38 
  39 #include <sys/systm.h>
  40 #include <sys/cred.h>
  41 #include <sys/vnode.h>
  42 #include <sys/vfs.h>
  43 #include <sys/filio.h>
  44 #include <sys/uio.h>
  45 #include <sys/dirent.h>
  46 #include <sys/errno.h>
  47 #include <sys/sunddi.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/kmem.h>
  50 #include <sys/cmn_err.h>
  51 #include <sys/vfs_opreg.h>
  52 #include <sys/policy.h>
  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 
  66 #include <netsmb/smb_osdep.h>
  67 #include <netsmb/smb.h>
  68 #include <netsmb/smb_conn.h>
  69 #include <netsmb/smb_subr.h>
  70 
  71 #include <smbfs/smbfs.h>
  72 #include <smbfs/smbfs_node.h>
  73 #include <smbfs/smbfs_subr.h>
  74 
  75 #include <sys/fs/smbfs_ioctl.h>
  76 #include <fs/fs_subr.h>
  77 
  78 /*
  79  * We assign directory offsets like the NFS client, where the
  80  * offset increments by _one_ after each directory entry.
  81  * Further, the entries "." and ".." are always at offsets
  82  * zero and one (respectively) and the "real" entries from
  83  * the server appear at offsets starting with two.  This
  84  * macro is used to initialize the n_dirofs field after
  85  * setting n_dirseq with a _findopen call.


 170 static int      smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
 171                         caller_context_t *, int);
 172 static int      smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
 173                         caller_context_t *, int);
 174 static int      smbfs_rwlock(vnode_t *, int, caller_context_t *);
 175 static void     smbfs_rwunlock(vnode_t *, int, caller_context_t *);
 176 static int      smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
 177 static int      smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
 178                         struct flk_callback *, cred_t *, caller_context_t *);
 179 static int      smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
 180                         cred_t *, caller_context_t *);
 181 static int      smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 182                         caller_context_t *);
 183 static int      smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 184                         caller_context_t *);
 185 static int      smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 186                         caller_context_t *);
 187 static int      smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 188                         caller_context_t *);
 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 
 222 /* Dummy function to use until correct function is ported in */
 223 int noop_vnodeop() {
 224         return (0);
 225 }
 226 
 227 struct vnodeops *smbfs_vnodeops = NULL;
 228 
 229 /*
 230  * Most unimplemented ops will return ENOSYS because of fs_nosys().
 231  * The only ops where that won't work are ACCESS (due to open(2)
 232  * failures) and ... (anything else left?)
 233  */
 234 const fs_operation_def_t smbfs_vnodeops_template[] = {
 235         { VOPNAME_OPEN,         { .vop_open = smbfs_open } },
 236         { VOPNAME_CLOSE,        { .vop_close = smbfs_close } },
 237         { VOPNAME_READ,         { .vop_read = smbfs_read } },
 238         { VOPNAME_WRITE,        { .vop_write = smbfs_write } },
 239         { VOPNAME_IOCTL,        { .vop_ioctl = smbfs_ioctl } },
 240         { VOPNAME_GETATTR,      { .vop_getattr = smbfs_getattr } },
 241         { VOPNAME_SETATTR,      { .vop_setattr = smbfs_setattr } },
 242         { VOPNAME_ACCESS,       { .vop_access = smbfs_access } },
 243         { VOPNAME_LOOKUP,       { .vop_lookup = smbfs_lookup } },
 244         { VOPNAME_CREATE,       { .vop_create = smbfs_create } },
 245         { VOPNAME_REMOVE,       { .vop_remove = smbfs_remove } },
 246         { VOPNAME_LINK,         { .error = fs_nosys } }, /* smbfs_link, */
 247         { VOPNAME_RENAME,       { .vop_rename = smbfs_rename } },
 248         { VOPNAME_MKDIR,        { .vop_mkdir = smbfs_mkdir } },
 249         { VOPNAME_RMDIR,        { .vop_rmdir = smbfs_rmdir } },
 250         { VOPNAME_READDIR,      { .vop_readdir = smbfs_readdir } },
 251         { VOPNAME_SYMLINK,      { .error = fs_nosys } }, /* smbfs_symlink, */
 252         { VOPNAME_READLINK,     { .error = fs_nosys } }, /* smbfs_readlink, */
 253         { VOPNAME_FSYNC,        { .vop_fsync = smbfs_fsync } },
 254         { VOPNAME_INACTIVE,     { .vop_inactive = smbfs_inactive } },
 255         { VOPNAME_FID,          { .error = fs_nosys } }, /* smbfs_fid, */
 256         { VOPNAME_RWLOCK,       { .vop_rwlock = smbfs_rwlock } },
 257         { VOPNAME_RWUNLOCK,     { .vop_rwunlock = smbfs_rwunlock } },
 258         { VOPNAME_SEEK,         { .vop_seek = smbfs_seek } },
 259         { VOPNAME_FRLOCK,       { .vop_frlock = smbfs_frlock } },
 260         { VOPNAME_SPACE,        { .vop_space = smbfs_space } },
 261         { VOPNAME_REALVP,       { .error = fs_nosys } }, /* smbfs_realvp, */
 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}},
 268         { VOPNAME_DUMP,         { .error = fs_nosys } }, /* smbfs_dump, */
 269         { VOPNAME_PATHCONF,     { .vop_pathconf = smbfs_pathconf } },
 270         { VOPNAME_PAGEIO,       { .error = fs_nosys } }, /* smbfs_pageio, */
 271         { VOPNAME_SETSECATTR,   { .vop_setsecattr = smbfs_setsecattr } },
 272         { VOPNAME_GETSECATTR,   { .vop_getsecattr = smbfs_getsecattr } },
 273         { VOPNAME_SHRLOCK,      { .vop_shrlock = smbfs_shrlock } },
 274         { NULL, NULL }
 275 };
 276 
 277 /*
 278  * XXX
 279  * When new and relevant functionality is enabled, we should be
 280  * calling vfs_set_feature() to inform callers that pieces of
 281  * functionality are available, per PSARC 2007/227.
 282  */
 283 /* ARGSUSED */
 284 static int
 285 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 286 {
 287         smbnode_t       *np;


 514         }
 515 
 516         /*
 517          * This (passed in) count is the ref. count from the
 518          * user's file_t before the closef call (fio.c).
 519          * We only care when the reference goes away.
 520          */
 521         if (count > 1)
 522                 return (0);
 523 
 524         /*
 525          * Decrement the reference count for the FID
 526          * and possibly do the OtW close.
 527          *
 528          * Exclusive lock for modifying n_fid stuff.
 529          * Don't want this one ever interruptible.
 530          */
 531         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
 532         smb_credinit(&scred, cr);
 533 
 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         }
 563 
 564         smb_credrele(&scred);
 565         smbfs_rw_exit(&np->r_lkserlock);
 566 
 567         return (0);
 568 }
 569 
 570 /*
 571  * Helper for smbfs_close.  Decrement the reference count
 572  * for an SMB-level file or directory ID, and when the last
 573  * reference for the fid goes away, do the OtW close.
 574  * Also called in smbfs_inactive (defensive cleanup).
 575  */
 576 static void
 577 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
 578 {
 579         smb_share_t     *ssp;
 580         cred_t          *oldcr;
 581         struct smbfs_fctx *fctx;
 582         int             error;


 631         }
 632 
 633         /* Allow next open to use any v_type. */
 634         np->n_ovtype = VNON;
 635 
 636         /*
 637          * Other "last close" stuff.
 638          */
 639         mutex_enter(&np->r_statelock);
 640         if (np->n_flag & NATTRCHANGED)
 641                 smbfs_attrcache_rm_locked(np);
 642         oldcr = np->r_cred;
 643         np->r_cred = NULL;
 644         mutex_exit(&np->r_statelock);
 645         if (oldcr != NULL)
 646                 crfree(oldcr);
 647 }
 648 
 649 /* ARGSUSED */
 650 static int
 651 smbfs_read(vnode_t * vp, struct uio * uiop, int ioflag, cred_t * cr,
 652            caller_context_t * ct)
 653 {
 654         struct smb_cred scred;
 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;
 668 
 669         np = VTOSMB(vp);
 670         smi = VTOSMI(vp);
 671         ssp = smi->smi_share;
 672 
 673         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 674                 return (EIO);
 675 
 676         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 677                 return (EIO);
 678 
 679         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
 680 
 681         if (vp->v_type != VREG)
 682                 return (EISDIR);
 683 
 684         if (uiop->uio_resid == 0)
 685                 return (0);
 686 
 687         /*
 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.

 690          */
 691         endoff = uiop->uio_loffset + uiop->uio_resid;
 692         if (uiop->uio_loffset < 0 || endoff < 0)
 693                 return (EINVAL);
 694 
 695         /* get vnode attributes from server */
 696         va.va_mask = AT_SIZE | AT_MTIME;
 697         if (error = smbfsgetattr(vp, &va, cr))
 698                 return (error);
 699 
 700         /* Update mtime with mtime from server here? */
 701 
 702         /* if offset is beyond EOF, read nothing */
 703         if (uiop->uio_loffset >= va.va_size)
 704                 return (0);
 705 
 706         /*
 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.

 709          */
 710         if (endoff > va.va_size) {
 711                 past_eof = (ssize_t) (endoff - va.va_size);
 712                 uiop->uio_resid -= past_eof;
 713         } else
 714                 past_eof = 0;
 715 
 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)))) {
 721 
 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);
 726 
 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         }
 774 
 775         /* undo adjustment of resid */
 776         uiop->uio_resid += past_eof;
 777 
 778         return (error);
 779 }
 780 

 781 /* ARGSUSED */
 782 static int
 783 smbfs_write(vnode_t * vp, struct uio * uiop, int ioflag, cred_t * cr,
 784             caller_context_t * ct)
 785 {
 786         struct smb_cred scred;
 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;
 803 
 804         np = VTOSMB(vp);
 805         smi = VTOSMI(vp);
 806         ssp = smi->smi_share;
 807 
 808         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 809                 return (EIO);
 810 
 811         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 812                 return (EIO);
 813 
 814         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
 815 
 816         if (vp->v_type != VREG)
 817                 return (EISDIR);
 818 
 819         if (uiop->uio_resid == 0)
 820                 return (0);
 821 
 822         /*
 823          * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
 824          */
 825         if (ioflag & (FAPPEND | FSYNC)) {
 826                 if (np->n_flag & NMODIFIED) {
 827                         smbfs_attrcache_remove(np);
 828                         /* XXX: smbfs_vinvalbuf? */
 829                 }
 830         }
 831         if (ioflag & FAPPEND) {
 832                 /*
 833                  * File size can be changed by another client
 834                  */
 835                 va.va_mask = AT_SIZE;
 836                 if (error = smbfsgetattr(vp, &va, cr))
 837                         return (error);
 838                 uiop->uio_loffset = va.va_size;
 839         }

 840         /*
 841          * Like NFS3, just check for 63-bit overflow.
 842          */
 843         endoff = uiop->uio_loffset + uiop->uio_resid;
 844         if (uiop->uio_loffset < 0 || endoff < 0)
 845                 return (EINVAL);
 846 
 847         /*
 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.


 855          */
 856         limit = uiop->uio_llimit;
 857         if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 858                 limit = MAXOFFSET_T;
 859         if (uiop->uio_loffset >= limit)
 860                 return (EFBIG);
 861         if (endoff > limit) {
 862                 past_limit = (ssize_t) (endoff - limit);
 863                 uiop->uio_resid -= past_limit;
 864         } else
 865                 past_limit = 0;
 866 
 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;
 877 
 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);
 882 
 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);
 889 
 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                         }
 900                 }

 901                 smb_credrele(&scred);
 902                 smbfs_rw_exit(&np->r_lkserlock);
 903 
 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         }
 971 
 972         /* undo adjustment of resid */
 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         }
 979 
 980         return (error);
 981 }
 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 }
1140 
1141 /* ARGSUSED */
1142 static int
1143 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
1144         cred_t *cr, int *rvalp, caller_context_t *ct)
1145 {
1146         int             error;
1147         smbmntinfo_t    *smi;
1148 
1149         smi = VTOSMI(vp);
1150 
1151         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1152                 return (EIO);
1153 
1154         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1155                 return (EIO);
1156 
1157         switch (cmd) {
1158                 /* First three from ZFS. XXX - need these? */
1159 


1709         switch (np->n_ovtype) {
1710         case VNON:
1711                 /* not open (OK) */
1712                 break;
1713 
1714         case VDIR:
1715                 if (np->n_dirrefs == 0)
1716                         break;
1717                 SMBVDEBUG("open dir: refs %d path %s\n",
1718                     np->n_dirrefs, np->n_rpath);
1719                 /* Force last close. */
1720                 np->n_dirrefs = 1;
1721                 smbfs_rele_fid(np, &scred);
1722                 break;
1723 
1724         case VREG:
1725                 if (np->n_fidrefs == 0)
1726                         break;
1727                 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
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                 }
1743                 /* Force last close. */
1744                 np->n_fidrefs = 1;
1745                 smbfs_rele_fid(np, &scred);
1746                 break;
1747 
1748         default:
1749                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1750                 np->n_ovtype = VNON;
1751                 break;
1752         }
1753 
1754         smb_credrele(&scred);
1755         smbfs_rw_exit(&np->r_lkserlock);
1756 
1757         smbfs_addfree(np);
1758 }
1759 
1760 /*
1761  * Remote file system operations having to do with directory manipulation.
1762  */


3468         return (error);
3469 }
3470 
3471 
3472 /*
3473  * XXX
3474  * This op should eventually support PSARC 2007/268.
3475  */
3476 static int
3477 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3478         caller_context_t *ct)
3479 {
3480         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3481                 return (EIO);
3482 
3483         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3484                 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3485         else
3486                 return (ENOSYS);
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 }