Print this page
cstyle
Fix missing logic for ESTALE and NFS_EOF
Implement ioctl _FIODIRECTIO
Kill flags arg in smbfs_purge_caches
Lots of comment cleanup
5404 smbfs needs mmap support
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>

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 ↓ 28 lines elided ↑ open up ↑
  29   29   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30   30   * SUCH DAMAGE.
  31   31   *
  32   32   * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
  33   33   */
  34   34  
  35   35  /*
  36   36   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37   37   */
  38   38  
       39 +/*
       40 + * Vnode operations
       41 + *
       42 + * This file is similar to nfs3_vnops.c
       43 + */
       44 +
       45 +#include <sys/param.h>
  39   46  #include <sys/systm.h>
  40   47  #include <sys/cred.h>
  41   48  #include <sys/vnode.h>
  42   49  #include <sys/vfs.h>
  43   50  #include <sys/filio.h>
  44   51  #include <sys/uio.h>
  45   52  #include <sys/dirent.h>
  46   53  #include <sys/errno.h>
  47   54  #include <sys/sunddi.h>
  48   55  #include <sys/sysmacros.h>
  49   56  #include <sys/kmem.h>
  50   57  #include <sys/cmn_err.h>
  51   58  #include <sys/vfs_opreg.h>
  52   59  #include <sys/policy.h>
       60 +#include <sys/sdt.h>
       61 +#include <sys/zone.h>
       62 +#include <sys/vmsystm.h>
  53   63  
       64 +#include <vm/hat.h>
       65 +#include <vm/as.h>
       66 +#include <vm/page.h>
       67 +#include <vm/pvn.h>
       68 +#include <vm/seg.h>
       69 +#include <vm/seg_map.h>
       70 +#include <vm/seg_kpm.h>
       71 +#include <vm/seg_vn.h>
       72 +
  54   73  #include <netsmb/smb_osdep.h>
  55   74  #include <netsmb/smb.h>
  56   75  #include <netsmb/smb_conn.h>
  57   76  #include <netsmb/smb_subr.h>
  58   77  
  59   78  #include <smbfs/smbfs.h>
  60   79  #include <smbfs/smbfs_node.h>
  61   80  #include <smbfs/smbfs_subr.h>
  62   81  
  63   82  #include <sys/fs/smbfs_ioctl.h>
↓ open down ↓ 30 lines elided ↑ open up ↑
  94  113          0
  95  114  };
  96  115  
  97  116  /*
  98  117   * Turning this on causes nodes to be created in the cache
  99  118   * during directory listings, normally avoiding a second
 100  119   * OtW attribute fetch just after a readdir.
 101  120   */
 102  121  int smbfs_fastlookup = 1;
 103  122  
      123 +struct vnodeops *smbfs_vnodeops = NULL;
      124 +
 104  125  /* local static function defines */
 105  126  
 106  127  static int      smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
 107  128                          cred_t *);
 108  129  static int      smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
 109  130                          int cache_ok, caller_context_t *);
 110  131  static int      smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
 111  132                          int flags);
 112  133  static int      smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp,
 113  134                          char *nnm, struct smb_cred *scred, int flags);
 114  135  static int      smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
 115  136  static int      smbfs_accessx(void *, int, cred_t *);
 116  137  static int      smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
 117  138                          caller_context_t *);
 118  139  static void     smbfs_rele_fid(smbnode_t *, struct smb_cred *);
 119  140  static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
 120  141  
      142 +static int      smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
      143 +                        cred_t *);
      144 +static int      smbfs_bio(struct buf *, int, cred_t *);
      145 +static int      smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
      146 +                        struct uio *uiop, int pgcreated);
      147 +
      148 +static int      smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
      149 +static int      smbfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
      150 +                        caller_context_t *);
      151 +static int      smbfs_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
      152 +                        page_t *[], size_t, struct seg *, caddr_t,
      153 +                        enum seg_rw, cred_t *);
      154 +static int      smbfs_putapage(vnode_t *, page_t *, u_offset_t *, size_t *,
      155 +                        int, cred_t *);
      156 +static void     smbfs_delmap_callback(struct as *, void *, uint_t);
      157 +
 121  158  /*
      159 + * Error flags used to pass information about certain special errors
      160 + * which need to be handled specially.
      161 + */
      162 +#define SMBFS_EOF                       -98
      163 +
      164 +/* When implementing OtW locks, make this a real function. */
      165 +#define smbfs_lm_has_sleep(vp) 0
      166 +
      167 +/*
 122  168   * These are the vnode ops routines which implement the vnode interface to
 123  169   * the networked file system.  These routines just take their parameters,
 124  170   * make them look networkish by putting the right info into interface structs,
 125  171   * and then calling the appropriate remote routine(s) to do the work.
 126  172   *
 127  173   * Note on directory name lookup cacheing:  If we detect a stale fhandle,
 128  174   * we purge the directory cache relative to that vnode.  This way, the
 129  175   * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
 130  176   * more details on smbnode locking.
 131  177   */
 132  178  
 133      -static int      smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
 134      -static int      smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
 135      -                        caller_context_t *);
 136      -static int      smbfs_read(vnode_t *, struct uio *, int, cred_t *,
 137      -                        caller_context_t *);
 138      -static int      smbfs_write(vnode_t *, struct uio *, int, cred_t *,
 139      -                        caller_context_t *);
 140      -static int      smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
 141      -                        caller_context_t *);
 142      -static int      smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
 143      -                        caller_context_t *);
 144      -static int      smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
 145      -                        caller_context_t *);
 146      -static int      smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
 147      -static int      smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
 148      -static void     smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
 149      -static int      smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
 150      -                        int, vnode_t *, cred_t *, caller_context_t *,
 151      -                        int *, pathname_t *);
 152      -static int      smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
 153      -                        int, vnode_t **, cred_t *, int, caller_context_t *,
 154      -                        vsecattr_t *);
 155      -static int      smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
 156      -                        int);
 157      -static int      smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
 158      -                        caller_context_t *, int);
 159      -static int      smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
 160      -                        cred_t *, caller_context_t *, int, vsecattr_t *);
 161      -static int      smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
 162      -                        caller_context_t *, int);
 163      -static int      smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
 164      -                        caller_context_t *, int);
 165      -static int      smbfs_rwlock(vnode_t *, int, caller_context_t *);
 166      -static void     smbfs_rwunlock(vnode_t *, int, caller_context_t *);
 167      -static int      smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
 168      -static int      smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
 169      -                        struct flk_callback *, cred_t *, caller_context_t *);
 170      -static int      smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
 171      -                        cred_t *, caller_context_t *);
 172      -static int      smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 173      -                        caller_context_t *);
 174      -static int      smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 175      -                        caller_context_t *);
 176      -static int      smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 177      -                        caller_context_t *);
 178      -static int      smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 179      -                        caller_context_t *);
 180  179  
 181      -/* Dummy function to use until correct function is ported in */
 182      -int noop_vnodeop() {
 183      -        return (0);
 184      -}
 185      -
 186      -struct vnodeops *smbfs_vnodeops = NULL;
 187      -
 188  180  /*
 189      - * Most unimplemented ops will return ENOSYS because of fs_nosys().
 190      - * The only ops where that won't work are ACCESS (due to open(2)
 191      - * failures) and ... (anything else left?)
 192      - */
 193      -const fs_operation_def_t smbfs_vnodeops_template[] = {
 194      -        { VOPNAME_OPEN,         { .vop_open = smbfs_open } },
 195      -        { VOPNAME_CLOSE,        { .vop_close = smbfs_close } },
 196      -        { VOPNAME_READ,         { .vop_read = smbfs_read } },
 197      -        { VOPNAME_WRITE,        { .vop_write = smbfs_write } },
 198      -        { VOPNAME_IOCTL,        { .vop_ioctl = smbfs_ioctl } },
 199      -        { VOPNAME_GETATTR,      { .vop_getattr = smbfs_getattr } },
 200      -        { VOPNAME_SETATTR,      { .vop_setattr = smbfs_setattr } },
 201      -        { VOPNAME_ACCESS,       { .vop_access = smbfs_access } },
 202      -        { VOPNAME_LOOKUP,       { .vop_lookup = smbfs_lookup } },
 203      -        { VOPNAME_CREATE,       { .vop_create = smbfs_create } },
 204      -        { VOPNAME_REMOVE,       { .vop_remove = smbfs_remove } },
 205      -        { VOPNAME_LINK,         { .error = fs_nosys } }, /* smbfs_link, */
 206      -        { VOPNAME_RENAME,       { .vop_rename = smbfs_rename } },
 207      -        { VOPNAME_MKDIR,        { .vop_mkdir = smbfs_mkdir } },
 208      -        { VOPNAME_RMDIR,        { .vop_rmdir = smbfs_rmdir } },
 209      -        { VOPNAME_READDIR,      { .vop_readdir = smbfs_readdir } },
 210      -        { VOPNAME_SYMLINK,      { .error = fs_nosys } }, /* smbfs_symlink, */
 211      -        { VOPNAME_READLINK,     { .error = fs_nosys } }, /* smbfs_readlink, */
 212      -        { VOPNAME_FSYNC,        { .vop_fsync = smbfs_fsync } },
 213      -        { VOPNAME_INACTIVE,     { .vop_inactive = smbfs_inactive } },
 214      -        { VOPNAME_FID,          { .error = fs_nosys } }, /* smbfs_fid, */
 215      -        { VOPNAME_RWLOCK,       { .vop_rwlock = smbfs_rwlock } },
 216      -        { VOPNAME_RWUNLOCK,     { .vop_rwunlock = smbfs_rwunlock } },
 217      -        { VOPNAME_SEEK,         { .vop_seek = smbfs_seek } },
 218      -        { VOPNAME_FRLOCK,       { .vop_frlock = smbfs_frlock } },
 219      -        { VOPNAME_SPACE,        { .vop_space = smbfs_space } },
 220      -        { VOPNAME_REALVP,       { .error = fs_nosys } }, /* smbfs_realvp, */
 221      -        { VOPNAME_GETPAGE,      { .error = fs_nosys } }, /* smbfs_getpage, */
 222      -        { VOPNAME_PUTPAGE,      { .error = fs_nosys } }, /* smbfs_putpage, */
 223      -        { VOPNAME_MAP,          { .error = fs_nosys } }, /* smbfs_map, */
 224      -        { VOPNAME_ADDMAP,       { .error = fs_nosys } }, /* smbfs_addmap, */
 225      -        { VOPNAME_DELMAP,       { .error = fs_nosys } }, /* smbfs_delmap, */
 226      -        { VOPNAME_DUMP,         { .error = fs_nosys } }, /* smbfs_dump, */
 227      -        { VOPNAME_PATHCONF,     { .vop_pathconf = smbfs_pathconf } },
 228      -        { VOPNAME_PAGEIO,       { .error = fs_nosys } }, /* smbfs_pageio, */
 229      -        { VOPNAME_SETSECATTR,   { .vop_setsecattr = smbfs_setsecattr } },
 230      -        { VOPNAME_GETSECATTR,   { .vop_getsecattr = smbfs_getsecattr } },
 231      -        { VOPNAME_SHRLOCK,      { .vop_shrlock = smbfs_shrlock } },
 232      -        { NULL, NULL }
 233      -};
 234      -
 235      -/*
 236  181   * XXX
 237  182   * When new and relevant functionality is enabled, we should be
 238  183   * calling vfs_set_feature() to inform callers that pieces of
 239  184   * functionality are available, per PSARC 2007/227.
 240  185   */
 241  186  /* ARGSUSED */
 242  187  static int
 243  188  smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 244  189  {
 245  190          smbnode_t       *np;
↓ open down ↓ 31 lines elided ↑ open up ↑
 277  222           */
 278  223          if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
 279  224                  return (EINTR);
 280  225          smb_credinit(&scred, cr);
 281  226  
 282  227          /*
 283  228           * Keep track of the vnode type at first open.
 284  229           * It may change later, and we need close to do
 285  230           * cleanup for the type we opened.  Also deny
 286  231           * open of new types until old type is closed.
 287      -         * XXX: Per-open instance nodes whould help.
 288  232           */
 289  233          if (np->n_ovtype == VNON) {
 290  234                  ASSERT(np->n_dirrefs == 0);
 291  235                  ASSERT(np->n_fidrefs == 0);
 292  236          } else if (np->n_ovtype != vp->v_type) {
 293  237                  SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
 294  238                      np->n_ovtype, vp->v_type);
 295  239                  error = EACCES;
 296  240                  goto out;
 297  241          }
↓ open down ↓ 118 lines elided ↑ open up ↑
 416  360  }
 417  361  
 418  362  /*ARGSUSED*/
 419  363  static int
 420  364  smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
 421  365          caller_context_t *ct)
 422  366  {
 423  367          smbnode_t       *np;
 424  368          smbmntinfo_t    *smi;
 425  369          struct smb_cred scred;
      370 +        int error = 0;
 426  371  
 427  372          np = VTOSMB(vp);
 428  373          smi = VTOSMI(vp);
 429  374  
 430  375          /*
 431  376           * Don't "bail out" for VFS_UNMOUNTED here,
 432  377           * as we want to do cleanup, etc.
 433  378           */
 434  379  
 435  380          /*
↓ open down ↓ 27 lines elided ↑ open up ↑
 463  408           * we are doing network locking and we need to release all
 464  409           * of the network locks.  All of the locks held by this
 465  410           * process on this file are released no matter what the
 466  411           * incoming reference count is.
 467  412           */
 468  413          if (smi->smi_flags & SMI_LLOCK) {
 469  414                  pid_t pid = ddi_get_pid();
 470  415                  cleanlocks(vp, pid, 0);
 471  416                  cleanshares(vp, pid);
 472  417          }
      418 +        /*
      419 +         * else doing OtW locking.  SMB servers drop all locks
      420 +         * on the file ID we close here, so no _lockrelease()
      421 +         */
 473  422  
 474  423          /*
 475  424           * This (passed in) count is the ref. count from the
 476  425           * user's file_t before the closef call (fio.c).
 477      -         * We only care when the reference goes away.
      426 +         * The rest happens only on last close.
 478  427           */
 479  428          if (count > 1)
 480  429                  return (0);
 481  430  
      431 +        /* NFS has DNLC purge here. */
      432 +
 482  433          /*
      434 +         * If the file was open for write and there are pages,
      435 +         * then make sure dirty pages written back.
      436 +         *
      437 +         * NFS does this async when "close-to-open" is off
      438 +         * (MI_NOCTO flag is set) to avoid blocking the caller.
      439 +         * For now, always do this synchronously (no B_ASYNC).
      440 +         */
      441 +        if ((flag & FWRITE) && vn_has_cached_data(vp)) {
      442 +                error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
      443 +                if (error == EAGAIN)
      444 +                        error = 0;
      445 +        }
      446 +        if (error == 0) {
      447 +                mutex_enter(&np->r_statelock);
      448 +                np->r_flags &= ~RSTALE;
      449 +                np->r_error = 0;
      450 +                mutex_exit(&np->r_statelock);
      451 +        }
      452 +
      453 +        /*
 483  454           * Decrement the reference count for the FID
 484  455           * and possibly do the OtW close.
 485  456           *
 486  457           * Exclusive lock for modifying n_fid stuff.
 487  458           * Don't want this one ever interruptible.
 488  459           */
 489  460          (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
 490  461          smb_credinit(&scred, cr);
 491  462  
 492  463          smbfs_rele_fid(np, &scred);
↓ open down ↓ 90 lines elided ↑ open up ↑
 583  554  {
 584  555          struct smb_cred scred;
 585  556          struct vattr    va;
 586  557          smbnode_t       *np;
 587  558          smbmntinfo_t    *smi;
 588  559          smb_share_t     *ssp;
 589  560          offset_t        endoff;
 590  561          ssize_t         past_eof;
 591  562          int             error;
 592  563  
      564 +        caddr_t         base;
      565 +        u_offset_t      off;
      566 +        size_t          n;
      567 +        int             on;
      568 +        uint_t          flags;
      569 +
 593  570          np = VTOSMB(vp);
 594  571          smi = VTOSMI(vp);
 595  572          ssp = smi->smi_share;
 596  573  
 597  574          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 598  575                  return (EIO);
 599  576  
 600  577          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 601  578                  return (EIO);
 602  579  
↓ open down ↓ 29 lines elided ↑ open up ↑
 632  609           * Limit the read to the remaining file size.
 633  610           * Do this by temporarily reducing uio_resid
 634  611           * by the amount the lies beyoned the EOF.
 635  612           */
 636  613          if (endoff > va.va_size) {
 637  614                  past_eof = (ssize_t)(endoff - va.va_size);
 638  615                  uiop->uio_resid -= past_eof;
 639  616          } else
 640  617                  past_eof = 0;
 641  618  
 642      -        /* Shared lock for n_fid use in smb_rwuio */
 643      -        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 644      -                return (EINTR);
 645      -        smb_credinit(&scred, cr);
      619 +        /*
      620 +         * Bypass VM if caching has been disabled (e.g., locking) or if
      621 +         * using client-side direct I/O and the file is not mmap'd and
      622 +         * there are no cached pages.
      623 +         */
      624 +        if ((vp->v_flag & VNOCACHE) ||
      625 +            (((np->r_flags & RDIRECTIO) || (smi->smi_flags & SMI_DIRECTIO)) &&
      626 +            np->r_mapcnt == 0 && np->r_inmap == 0 &&
      627 +            !vn_has_cached_data(vp))) {
 646  628  
 647      -        /* After reconnect, n_fid is invalid */
 648      -        if (np->n_vcgenid != ssp->ss_vcgenid)
 649      -                error = ESTALE;
 650      -        else
 651      -                error = smb_rwuio(ssp, np->n_fid, UIO_READ,
 652      -                    uiop, &scred, smb_timo_read);
      629 +                /* Shared lock for n_fid use in smb_rwuio */
      630 +                if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
      631 +                        return (EINTR);
      632 +                smb_credinit(&scred, cr);
 653  633  
 654      -        smb_credrele(&scred);
 655      -        smbfs_rw_exit(&np->r_lkserlock);
      634 +                /* After reconnect, n_fid is invalid */
      635 +                if (np->n_vcgenid != ssp->ss_vcgenid)
      636 +                        error = ESTALE;
      637 +                else
      638 +                        error = smb_rwuio(ssp, np->n_fid, UIO_READ,
      639 +                            uiop, &scred, smb_timo_read);
 656  640  
      641 +                smb_credrele(&scred);
      642 +                smbfs_rw_exit(&np->r_lkserlock);
      643 +
      644 +                /* undo adjustment of resid */
      645 +                uiop->uio_resid += past_eof;
      646 +
      647 +                return (error);
      648 +        }
      649 +
      650 +        /* (else) Do I/O through segmap. */
      651 +        do {
      652 +                off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
      653 +                on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
      654 +                n = MIN(MAXBSIZE - on, uiop->uio_resid);
      655 +
      656 +                error = smbfs_validate_caches(vp, cr);
      657 +                if (error)
      658 +                        break;
      659 +
      660 +                /* NFS waits for RINCACHEPURGE here. */
      661 +
      662 +                if (vpm_enable) {
      663 +                        /*
      664 +                         * Copy data.
      665 +                         */
      666 +                        error = vpm_data_copy(vp, off + on, n, uiop,
      667 +                            1, NULL, 0, S_READ);
      668 +                } else {
      669 +                        base = segmap_getmapflt(segkmap, vp, off + on, n, 1,
      670 +                            S_READ);
      671 +
      672 +                        error = uiomove(base + on, n, UIO_READ, uiop);
      673 +                }
      674 +
      675 +                if (!error) {
      676 +                        /*
      677 +                         * If read a whole block or read to eof,
      678 +                         * won't need this buffer again soon.
      679 +                         */
      680 +                        mutex_enter(&np->r_statelock);
      681 +                        if (n + on == MAXBSIZE ||
      682 +                            uiop->uio_loffset == np->r_size)
      683 +                                flags = SM_DONTNEED;
      684 +                        else
      685 +                                flags = 0;
      686 +                        mutex_exit(&np->r_statelock);
      687 +                        if (vpm_enable) {
      688 +                                error = vpm_sync_pages(vp, off, n, flags);
      689 +                        } else {
      690 +                                error = segmap_release(segkmap, base, flags);
      691 +                        }
      692 +                } else {
      693 +                        if (vpm_enable) {
      694 +                                (void) vpm_sync_pages(vp, off, n, 0);
      695 +                        } else {
      696 +                                (void) segmap_release(segkmap, base, 0);
      697 +                        }
      698 +                }
      699 +        } while (!error && uiop->uio_resid > 0);
      700 +
 657  701          /* undo adjustment of resid */
 658  702          uiop->uio_resid += past_eof;
 659  703  
 660  704          return (error);
 661  705  }
 662  706  
 663  707  
 664  708  /* ARGSUSED */
 665  709  static int
 666  710  smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 667  711          caller_context_t *ct)
 668  712  {
 669  713          struct smb_cred scred;
 670      -        struct vattr    va;
      714 +        struct vattr    va;
 671  715          smbnode_t       *np;
 672  716          smbmntinfo_t    *smi;
 673  717          smb_share_t     *ssp;
 674  718          offset_t        endoff, limit;
 675  719          ssize_t         past_limit;
 676  720          int             error, timo;
      721 +        caddr_t         base;
      722 +        u_offset_t      off;
      723 +        size_t          n;
      724 +        int             on;
      725 +        uint_t          flags;
      726 +        u_offset_t      last_off;
      727 +        size_t          last_resid;
      728 +        uint_t          bsize;
 677  729  
 678  730          np = VTOSMB(vp);
 679  731          smi = VTOSMI(vp);
 680  732          ssp = smi->smi_share;
 681  733  
 682  734          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 683  735                  return (EIO);
 684  736  
 685  737          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 686  738                  return (EIO);
↓ open down ↓ 5 lines elided ↑ open up ↑
 692  744  
 693  745          if (uiop->uio_resid == 0)
 694  746                  return (0);
 695  747  
 696  748          /*
 697  749           * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
 698  750           */
 699  751          if (ioflag & (FAPPEND | FSYNC)) {
 700  752                  if (np->n_flag & NMODIFIED) {
 701  753                          smbfs_attrcache_remove(np);
 702      -                        /* XXX: smbfs_vinvalbuf? */
 703  754                  }
 704  755          }
 705  756          if (ioflag & FAPPEND) {
 706  757                  /*
 707  758                   * File size can be changed by another client
      759 +                 *
      760 +                 * Todo: Consider redesigning this to use a
      761 +                 * handle opened for append instead.
 708  762                   */
 709  763                  va.va_mask = AT_SIZE;
 710  764                  if (error = smbfsgetattr(vp, &va, cr))
 711  765                          return (error);
 712  766                  uiop->uio_loffset = va.va_size;
 713  767          }
 714  768  
 715  769          /*
 716  770           * Like NFS3, just check for 63-bit overflow.
 717  771           */
↓ open down ↓ 3 lines elided ↑ open up ↑
 721  775  
 722  776          /*
 723  777           * Check to make sure that the process will not exceed
 724  778           * its limit on file size.  It is okay to write up to
 725  779           * the limit, but not beyond.  Thus, the write which
 726  780           * reaches the limit will be short and the next write
 727  781           * will return an error.
 728  782           *
 729  783           * So if we're starting at or beyond the limit, EFBIG.
 730  784           * Otherwise, temporarily reduce resid to the amount
 731      -         * the falls after the limit.
      785 +         * that is after the limit.
 732  786           */
 733  787          limit = uiop->uio_llimit;
 734  788          if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 735  789                  limit = MAXOFFSET_T;
 736      -        if (uiop->uio_loffset >= limit)
      790 +        if (uiop->uio_loffset >= limit) {
      791 +                proc_t *p = ttoproc(curthread);
      792 +
      793 +                mutex_enter(&p->p_lock);
      794 +                (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE],
      795 +                    p->p_rctls, p, RCA_UNSAFE_SIGINFO);
      796 +                mutex_exit(&p->p_lock);
 737  797                  return (EFBIG);
      798 +        }
 738  799          if (endoff > limit) {
 739  800                  past_limit = (ssize_t)(endoff - limit);
 740  801                  uiop->uio_resid -= past_limit;
 741  802          } else
 742  803                  past_limit = 0;
 743  804  
 744      -        /* Timeout: longer for append. */
 745      -        timo = smb_timo_write;
 746      -        if (endoff > np->r_size)
 747      -                timo = smb_timo_append;
      805 +        /*
      806 +         * Bypass VM if caching has been disabled (e.g., locking) or if
      807 +         * using client-side direct I/O and the file is not mmap'd and
      808 +         * there are no cached pages.
      809 +         */
      810 +        if ((vp->v_flag & VNOCACHE) ||
      811 +            (((np->r_flags & RDIRECTIO) || (smi->smi_flags & SMI_DIRECTIO)) &&
      812 +            np->r_mapcnt == 0 && np->r_inmap == 0 &&
      813 +            !vn_has_cached_data(vp))) {
 748  814  
      815 +smbfs_fwrite:
      816 +                if (np->r_flags & RSTALE) {
      817 +                        last_resid = uiop->uio_resid;
      818 +                        last_off = uiop->uio_loffset;
      819 +                        error = np->r_error;
      820 +                        /*
      821 +                         * A close may have cleared r_error, if so,
      822 +                         * propagate ESTALE error return properly
      823 +                         */
      824 +                        if (error == 0)
      825 +                                error = ESTALE;
      826 +                        goto bottom;
      827 +                }
      828 +
      829 +                /* Timeout: longer for append. */
      830 +                timo = smb_timo_write;
      831 +                if (endoff > np->r_size)
      832 +                        timo = smb_timo_append;
      833 +
      834 +                /* Shared lock for n_fid use in smb_rwuio */
      835 +                if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
      836 +                        return (EINTR);
      837 +                smb_credinit(&scred, cr);
      838 +
      839 +                /* After reconnect, n_fid is invalid */
      840 +                if (np->n_vcgenid != ssp->ss_vcgenid)
      841 +                        error = ESTALE;
      842 +                else
      843 +                        error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
      844 +                            uiop, &scred, timo);
      845 +
      846 +                if (error == 0) {
      847 +                        mutex_enter(&np->r_statelock);
      848 +                        np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
      849 +                        if (uiop->uio_loffset > (offset_t)np->r_size)
      850 +                                np->r_size = (len_t)uiop->uio_loffset;
      851 +                        mutex_exit(&np->r_statelock);
      852 +                        if (ioflag & (FSYNC | FDSYNC)) {
      853 +                                /* Don't error the I/O if this fails. */
      854 +                                (void) smbfs_smb_flush(np, &scred);
      855 +                        }
      856 +                }
      857 +
      858 +                smb_credrele(&scred);
      859 +                smbfs_rw_exit(&np->r_lkserlock);
      860 +
      861 +                /* undo adjustment of resid */
      862 +                uiop->uio_resid += past_limit;
      863 +
      864 +                return (error);
      865 +        }
      866 +
      867 +        /* (else) Do I/O through segmap. */
      868 +        bsize = vp->v_vfsp->vfs_bsize;
      869 +
      870 +        do {
      871 +                off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
      872 +                on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
      873 +                n = MIN(MAXBSIZE - on, uiop->uio_resid);
      874 +
      875 +                last_resid = uiop->uio_resid;
      876 +                last_off = uiop->uio_loffset;
      877 +
      878 +                if (np->r_flags & RSTALE) {
      879 +                        error = np->r_error;
      880 +                        /*
      881 +                         * A close may have cleared r_error, if so,
      882 +                         * propagate ESTALE error return properly
      883 +                         */
      884 +                        if (error == 0)
      885 +                                error = ESTALE;
      886 +                        break;
      887 +                }
      888 +
      889 +                /*
      890 +                 * From NFS: Don't create dirty pages faster than they
      891 +                 * can be cleaned.
      892 +                 *
      893 +                 * Here NFS also checks for async writes (np->r_awcount)
      894 +                 */
      895 +                mutex_enter(&np->r_statelock);
      896 +                while (np->r_gcount > 0) {
      897 +                        if (SMBINTR(vp)) {
      898 +                                klwp_t *lwp = ttolwp(curthread);
      899 +
      900 +                                if (lwp != NULL)
      901 +                                        lwp->lwp_nostop++;
      902 +                                if (!cv_wait_sig(&np->r_cv, &np->r_statelock)) {
      903 +                                        mutex_exit(&np->r_statelock);
      904 +                                        if (lwp != NULL)
      905 +                                                lwp->lwp_nostop--;
      906 +                                        error = EINTR;
      907 +                                        goto bottom;
      908 +                                }
      909 +                                if (lwp != NULL)
      910 +                                        lwp->lwp_nostop--;
      911 +                        } else
      912 +                                cv_wait(&np->r_cv, &np->r_statelock);
      913 +                }
      914 +                mutex_exit(&np->r_statelock);
      915 +
      916 +                /*
      917 +                 * Touch the page and fault it in if it is not in core
      918 +                 * before segmap_getmapflt or vpm_data_copy can lock it.
      919 +                 * This is to avoid the deadlock if the buffer is mapped
      920 +                 * to the same file through mmap which we want to write.
      921 +                 */
      922 +                uio_prefaultpages((long)n, uiop);
      923 +
      924 +                if (vpm_enable) {
      925 +                        /*
      926 +                         * It will use kpm mappings, so no need to
      927 +                         * pass an address.
      928 +                         */
      929 +                        error = smbfs_writenp(np, NULL, n, uiop, 0);
      930 +                } else {
      931 +                        if (segmap_kpm) {
      932 +                                int pon = uiop->uio_loffset & PAGEOFFSET;
      933 +                                size_t pn = MIN(PAGESIZE - pon,
      934 +                                    uiop->uio_resid);
      935 +                                int pagecreate;
      936 +
      937 +                                mutex_enter(&np->r_statelock);
      938 +                                pagecreate = (pon == 0) && (pn == PAGESIZE ||
      939 +                                    uiop->uio_loffset + pn >= np->r_size);
      940 +                                mutex_exit(&np->r_statelock);
      941 +
      942 +                                base = segmap_getmapflt(segkmap, vp, off + on,
      943 +                                    pn, !pagecreate, S_WRITE);
      944 +
      945 +                                error = smbfs_writenp(np, base + pon, n, uiop,
      946 +                                    pagecreate);
      947 +
      948 +                        } else {
      949 +                                base = segmap_getmapflt(segkmap, vp, off + on,
      950 +                                    n, 0, S_READ);
      951 +                                error = smbfs_writenp(np, base + on, n, uiop, 0);
      952 +                        }
      953 +                }
      954 +
      955 +                if (!error) {
      956 +                        if (smi->smi_flags & SMI_NOAC)
      957 +                                flags = SM_WRITE;
      958 +                        else if ((uiop->uio_loffset % bsize) == 0 ||
      959 +                            IS_SWAPVP(vp)) {
      960 +                                /*
      961 +                                 * Have written a whole block.
      962 +                                 * Start an asynchronous write
      963 +                                 * and mark the buffer to
      964 +                                 * indicate that it won't be
      965 +                                 * needed again soon.
      966 +                                 */
      967 +                                flags = SM_WRITE | SM_ASYNC | SM_DONTNEED;
      968 +                        } else
      969 +                                flags = 0;
      970 +                        if ((ioflag & (FSYNC|FDSYNC)) ||
      971 +                            (np->r_flags & ROUTOFSPACE)) {
      972 +                                flags &= ~SM_ASYNC;
      973 +                                flags |= SM_WRITE;
      974 +                        }
      975 +                        if (vpm_enable) {
      976 +                                error = vpm_sync_pages(vp, off, n, flags);
      977 +                        } else {
      978 +                                error = segmap_release(segkmap, base, flags);
      979 +                        }
      980 +                } else {
      981 +                        if (vpm_enable) {
      982 +                                (void) vpm_sync_pages(vp, off, n, 0);
      983 +                        } else {
      984 +                                (void) segmap_release(segkmap, base, 0);
      985 +                        }
      986 +                        /*
      987 +                         * In the event that we got an access error while
      988 +                         * faulting in a page for a write-only file just
      989 +                         * force a write.
      990 +                         */
      991 +                        if (error == EACCES)
      992 +                                goto smbfs_fwrite;
      993 +                }
      994 +        } while (!error && uiop->uio_resid > 0);
      995 +
      996 +bottom:
      997 +        /* undo adjustment of resid */
      998 +        if (error) {
      999 +                uiop->uio_resid = last_resid + past_limit;
     1000 +                uiop->uio_loffset = last_off;
     1001 +        } else {
     1002 +                uiop->uio_resid += past_limit;
     1003 +        }
     1004 +
     1005 +        return (error);
     1006 +}
     1007 +
     1008 +/*
     1009 + * Like nfs_client.c: writerp()
     1010 + *
     1011 + * Write by creating pages and uiomove data onto them.
     1012 + */
     1013 +
     1014 +int
     1015 +smbfs_writenp(smbnode_t *np, caddr_t base, int tcount, struct uio *uio,
     1016 +    int pgcreated)
     1017 +{
     1018 +        int             pagecreate;
     1019 +        int             n;
     1020 +        int             saved_n;
     1021 +        caddr_t         saved_base;
     1022 +        u_offset_t      offset;
     1023 +        int             error;
     1024 +        int             sm_error;
     1025 +        vnode_t         *vp = SMBTOV(np);
     1026 +
     1027 +        ASSERT(tcount <= MAXBSIZE && tcount <= uio->uio_resid);
     1028 +        ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
     1029 +        if (!vpm_enable) {
     1030 +                ASSERT(((uintptr_t)base & MAXBOFFSET) + tcount <= MAXBSIZE);
     1031 +        }
     1032 +
     1033 +        /*
     1034 +         * Move bytes in at most PAGESIZE chunks. We must avoid
     1035 +         * spanning pages in uiomove() because page faults may cause
     1036 +         * the cache to be invalidated out from under us. The r_size is not
     1037 +         * updated until after the uiomove. If we push the last page of a
     1038 +         * file before r_size is correct, we will lose the data written past
     1039 +         * the current (and invalid) r_size.
     1040 +         */
     1041 +        do {
     1042 +                offset = uio->uio_loffset;
     1043 +                pagecreate = 0;
     1044 +
     1045 +                /*
     1046 +                 * n is the number of bytes required to satisfy the request
     1047 +                 *   or the number of bytes to fill out the page.
     1048 +                 */
     1049 +                n = (int)MIN((PAGESIZE - (offset & PAGEOFFSET)), tcount);
     1050 +
     1051 +                /*
     1052 +                 * Check to see if we can skip reading in the page
     1053 +                 * and just allocate the memory.  We can do this
     1054 +                 * if we are going to rewrite the entire mapping
     1055 +                 * or if we are going to write to or beyond the current
     1056 +                 * end of file from the beginning of the mapping.
     1057 +                 *
     1058 +                 * The read of r_size is now protected by r_statelock.
     1059 +                 */
     1060 +                mutex_enter(&np->r_statelock);
     1061 +                /*
     1062 +                 * When pgcreated is nonzero the caller has already done
     1063 +                 * a segmap_getmapflt with forcefault 0 and S_WRITE. With
     1064 +                 * segkpm this means we already have at least one page
     1065 +                 * created and mapped at base.
     1066 +                 */
     1067 +                pagecreate = pgcreated ||
     1068 +                    ((offset & PAGEOFFSET) == 0 &&
     1069 +                    (n == PAGESIZE || ((offset + n) >= np->r_size)));
     1070 +
     1071 +                mutex_exit(&np->r_statelock);
     1072 +                if (!vpm_enable && pagecreate) {
     1073 +                        /*
     1074 +                         * The last argument tells segmap_pagecreate() to
     1075 +                         * always lock the page, as opposed to sometimes
     1076 +                         * returning with the page locked. This way we avoid a
     1077 +                         * fault on the ensuing uiomove(), but also
     1078 +                         * more importantly (to fix bug 1094402) we can
     1079 +                         * call segmap_fault() to unlock the page in all
     1080 +                         * cases. An alternative would be to modify
     1081 +                         * segmap_pagecreate() to tell us when it is
     1082 +                         * locking a page, but that's a fairly major
     1083 +                         * interface change.
     1084 +                         */
     1085 +                        if (pgcreated == 0)
     1086 +                                (void) segmap_pagecreate(segkmap, base,
     1087 +                                    (uint_t)n, 1);
     1088 +                        saved_base = base;
     1089 +                        saved_n = n;
     1090 +                }
     1091 +
     1092 +                /*
     1093 +                 * The number of bytes of data in the last page can not
     1094 +                 * be accurately be determined while page is being
     1095 +                 * uiomove'd to and the size of the file being updated.
     1096 +                 * Thus, inform threads which need to know accurately
     1097 +                 * how much data is in the last page of the file.  They
     1098 +                 * will not do the i/o immediately, but will arrange for
     1099 +                 * the i/o to happen later when this modify operation
     1100 +                 * will have finished.
     1101 +                 */
     1102 +                ASSERT(!(np->r_flags & RMODINPROGRESS));
     1103 +                mutex_enter(&np->r_statelock);
     1104 +                np->r_flags |= RMODINPROGRESS;
     1105 +                np->r_modaddr = (offset & MAXBMASK);
     1106 +                mutex_exit(&np->r_statelock);
     1107 +
     1108 +                if (vpm_enable) {
     1109 +                        /*
     1110 +                         * Copy data. If new pages are created, part of
     1111 +                         * the page that is not written will be initizliazed
     1112 +                         * with zeros.
     1113 +                         */
     1114 +                        error = vpm_data_copy(vp, offset, n, uio,
     1115 +                            !pagecreate, NULL, 0, S_WRITE);
     1116 +                } else {
     1117 +                        error = uiomove(base, n, UIO_WRITE, uio);
     1118 +                }
     1119 +
     1120 +                /*
     1121 +                 * r_size is the maximum number of
     1122 +                 * bytes known to be in the file.
     1123 +                 * Make sure it is at least as high as the
     1124 +                 * first unwritten byte pointed to by uio_loffset.
     1125 +                 */
     1126 +                mutex_enter(&np->r_statelock);
     1127 +                if (np->r_size < uio->uio_loffset)
     1128 +                        np->r_size = uio->uio_loffset;
     1129 +                np->r_flags &= ~RMODINPROGRESS;
     1130 +                np->r_flags |= RDIRTY;
     1131 +                mutex_exit(&np->r_statelock);
     1132 +
     1133 +                /* n = # of bytes written */
     1134 +                n = (int)(uio->uio_loffset - offset);
     1135 +
     1136 +                if (!vpm_enable) {
     1137 +                        base += n;
     1138 +                }
     1139 +                tcount -= n;
     1140 +                /*
     1141 +                 * If we created pages w/o initializing them completely,
     1142 +                 * we need to zero the part that wasn't set up.
     1143 +                 * This happens on a most EOF write cases and if
     1144 +                 * we had some sort of error during the uiomove.
     1145 +                 */
     1146 +                if (!vpm_enable && pagecreate) {
     1147 +                        if ((uio->uio_loffset & PAGEOFFSET) || n == 0)
     1148 +                                (void) kzero(base, PAGESIZE - n);
     1149 +
     1150 +                        if (pgcreated) {
     1151 +                                /*
     1152 +                                 * Caller is responsible for this page,
     1153 +                                 * it was not created in this loop.
     1154 +                                 */
     1155 +                                pgcreated = 0;
     1156 +                        } else {
     1157 +                                /*
     1158 +                                 * For bug 1094402: segmap_pagecreate locks
     1159 +                                 * page. Unlock it. This also unlocks the
     1160 +                                 * pages allocated by page_create_va() in
     1161 +                                 * segmap_pagecreate().
     1162 +                                 */
     1163 +                                sm_error = segmap_fault(kas.a_hat, segkmap,
     1164 +                                    saved_base, saved_n,
     1165 +                                    F_SOFTUNLOCK, S_WRITE);
     1166 +                                if (error == 0)
     1167 +                                        error = sm_error;
     1168 +                        }
     1169 +                }
     1170 +        } while (tcount > 0 && error == 0);
     1171 +
     1172 +        return (error);
     1173 +}
     1174 +
     1175 +/*
     1176 + * Flags are composed of {B_ASYNC, B_INVAL, B_FREE, B_DONTNEED}
     1177 + * Like nfs3_rdwrlbn()
     1178 + */
     1179 +static int
     1180 +smbfs_rdwrlbn(vnode_t *vp, page_t *pp, u_offset_t off, size_t len,
     1181 +        int flags, cred_t *cr)
     1182 +{
     1183 +        smbmntinfo_t    *smi = VTOSMI(vp);
     1184 +        struct buf *bp;
     1185 +        int error;
     1186 +        int sync;
     1187 +
     1188 +        if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
     1189 +                return (EIO);
     1190 +
     1191 +        if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
     1192 +                return (EIO);
     1193 +
     1194 +        bp = pageio_setup(pp, len, vp, flags);
     1195 +        ASSERT(bp != NULL);
     1196 +
     1197 +        /*
     1198 +         * pageio_setup should have set b_addr to 0.  This
     1199 +         * is correct since we want to do I/O on a page
     1200 +         * boundary.  bp_mapin will use this addr to calculate
     1201 +         * an offset, and then set b_addr to the kernel virtual
     1202 +         * address it allocated for us.
     1203 +         */
     1204 +        ASSERT(bp->b_un.b_addr == 0);
     1205 +
     1206 +        bp->b_edev = 0;
     1207 +        bp->b_dev = 0;
     1208 +        bp->b_lblkno = lbtodb(off);
     1209 +        bp->b_file = vp;
     1210 +        bp->b_offset = (offset_t)off;
     1211 +        bp_mapin(bp);
     1212 +
     1213 +        /*
     1214 +         * Calculate the desired level of stability to write data.
     1215 +         */
     1216 +        if ((flags & (B_WRITE|B_ASYNC)) == (B_WRITE|B_ASYNC) &&
     1217 +            freemem > desfree) {
     1218 +                sync = 0;
     1219 +        } else {
     1220 +                sync = 1;
     1221 +        }
     1222 +
     1223 +        error = smbfs_bio(bp, sync, cr);
     1224 +
     1225 +        bp_mapout(bp);
     1226 +        pageio_done(bp);
     1227 +
     1228 +        return (error);
     1229 +}
     1230 +
     1231 +
     1232 +/*
     1233 + * Corresponds to nfs3_vnopc.c : nfs3_bio(), though the NFS code
     1234 + * uses nfs3read()/nfs3write() where we use smb_rwuio().  Also,
     1235 + * NFS has this later in the file.  Move it up here closer to
     1236 + * the one call site just above.
     1237 + */
     1238 +
     1239 +static int
     1240 +smbfs_bio(struct buf *bp, int sync, cred_t *cr)
     1241 +{
     1242 +        struct iovec aiov[1];
     1243 +        struct uio  auio;
     1244 +        struct smb_cred scred;
     1245 +        smbnode_t *np = VTOSMB(bp->b_vp);
     1246 +        smbmntinfo_t *smi = np->n_mount;
     1247 +        smb_share_t *ssp = smi->smi_share;
     1248 +        offset_t offset;
     1249 +        offset_t endoff;
     1250 +        size_t count;
     1251 +        size_t past_eof;
     1252 +        int error;
     1253 +
     1254 +        ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
     1255 +
     1256 +        offset = ldbtob(bp->b_lblkno);
     1257 +        count = bp->b_bcount;
     1258 +        endoff = offset + count;
     1259 +        if (offset < 0 || endoff < 0)
     1260 +                return (EINVAL);
     1261 +
     1262 +        /*
     1263 +         * Limit file I/O to the remaining file size, but see
     1264 +         * the notes in smbfs_getpage about SMBFS_EOF.
     1265 +         */
     1266 +        mutex_enter(&np->r_statelock);
     1267 +        if (offset >= np->r_size) {
     1268 +                mutex_exit(&np->r_statelock);
     1269 +                if (bp->b_flags & B_READ) {
     1270 +                        return (SMBFS_EOF);
     1271 +                } else {
     1272 +                        return (EINVAL);
     1273 +                }
     1274 +        }
     1275 +        if (endoff > np->r_size) {
     1276 +                past_eof = (size_t)(endoff - np->r_size);
     1277 +                count -= past_eof;
     1278 +        } else
     1279 +                past_eof = 0;
     1280 +        mutex_exit(&np->r_statelock);
     1281 +        ASSERT(count > 0);
     1282 +
     1283 +        /* Caller did bpmapin().  Mapped address is... */
     1284 +        aiov[0].iov_base = bp->b_un.b_addr;
     1285 +        aiov[0].iov_len = count;
     1286 +        auio.uio_iov = aiov;
     1287 +        auio.uio_iovcnt = 1;
     1288 +        auio.uio_loffset = offset;
     1289 +        auio.uio_segflg = UIO_SYSSPACE;
     1290 +        auio.uio_fmode = 0;
     1291 +        auio.uio_resid = count;
     1292 +
 749 1293          /* Shared lock for n_fid use in smb_rwuio */
 750      -        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
     1294 +        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER,
     1295 +            smi->smi_flags & SMI_INT))
 751 1296                  return (EINTR);
 752 1297          smb_credinit(&scred, cr);
 753 1298  
 754      -        /* After reconnect, n_fid is invalid */
 755      -        if (np->n_vcgenid != ssp->ss_vcgenid)
 756      -                error = ESTALE;
 757      -        else
 758      -                error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
 759      -                    uiop, &scred, timo);
     1299 +        DTRACE_IO1(start, struct buf *, bp);
 760 1300  
 761      -        if (error == 0) {
 762      -                mutex_enter(&np->r_statelock);
 763      -                np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
 764      -                if (uiop->uio_loffset > (offset_t)np->r_size)
 765      -                        np->r_size = (len_t)uiop->uio_loffset;
 766      -                mutex_exit(&np->r_statelock);
 767      -                if (ioflag & (FSYNC|FDSYNC)) {
 768      -                        /* Don't error the I/O if this fails. */
     1301 +        if (bp->b_flags & B_READ) {
     1302 +
     1303 +                /* After reconnect, n_fid is invalid */
     1304 +                if (np->n_vcgenid != ssp->ss_vcgenid)
     1305 +                        error = ESTALE;
     1306 +                else
     1307 +                        error = smb_rwuio(ssp, np->n_fid, UIO_READ,
     1308 +                            &auio, &scred, smb_timo_read);
     1309 +
     1310 +                /* Like NFS, only set b_error here. */
     1311 +                bp->b_error = error;
     1312 +                bp->b_resid = auio.uio_resid;
     1313 +
     1314 +                if (!error && auio.uio_resid != 0)
     1315 +                        error = EIO;
     1316 +                if (!error && past_eof != 0) {
     1317 +                        /* Zero the memory beyond EOF. */
     1318 +                        bzero(bp->b_un.b_addr + count, past_eof);
     1319 +                }
     1320 +        } else {
     1321 +
     1322 +                /* After reconnect, n_fid is invalid */
     1323 +                if (np->n_vcgenid != ssp->ss_vcgenid)
     1324 +                        error = ESTALE;
     1325 +                else
     1326 +                        error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
     1327 +                            &auio, &scred, smb_timo_write);
     1328 +
     1329 +                /* Like NFS, only set b_error here. */
     1330 +                bp->b_error = error;
     1331 +                bp->b_resid = auio.uio_resid;
     1332 +
     1333 +                if (!error && auio.uio_resid != 0)
     1334 +                        error = EIO;
     1335 +                if (!error && sync) {
 769 1336                          (void) smbfs_smb_flush(np, &scred);
 770 1337                  }
 771 1338          }
 772 1339  
     1340 +        /*
     1341 +         * This comes from nfs3_commit()
     1342 +         */
     1343 +        if (error != 0) {
     1344 +                mutex_enter(&np->r_statelock);
     1345 +                if (error == ESTALE)
     1346 +                        np->r_flags |= RSTALE;
     1347 +                if (!np->r_error)
     1348 +                        np->r_error = error;
     1349 +                mutex_exit(&np->r_statelock);
     1350 +                bp->b_flags |= B_ERROR;
     1351 +        }
     1352 +
     1353 +        DTRACE_IO1(done, struct buf *, bp);
     1354 +
 773 1355          smb_credrele(&scred);
 774 1356          smbfs_rw_exit(&np->r_lkserlock);
 775 1357  
 776      -        /* undo adjustment of resid */
 777      -        uiop->uio_resid += past_limit;
     1358 +        if (error == ESTALE)
     1359 +                smbfs_attrcache_remove(np);
 778 1360  
 779 1361          return (error);
 780 1362  }
 781 1363  
     1364 +/*
     1365 + * Here NFS has: nfs3write, nfs3read
     1366 + * We use smb_rwuio instead.
     1367 + */
 782 1368  
 783 1369  /* ARGSUSED */
 784 1370  static int
 785 1371  smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
 786 1372          cred_t *cr, int *rvalp, caller_context_t *ct)
 787 1373  {
 788 1374          int             error;
 789 1375          smbmntinfo_t    *smi;
 790 1376  
 791 1377          smi = VTOSMI(vp);
 792 1378  
 793 1379          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 794 1380                  return (EIO);
 795 1381  
 796 1382          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 797 1383                  return (EIO);
 798 1384  
 799 1385          switch (cmd) {
 800      -                /* First three from ZFS. XXX - need these? */
 801 1386  
 802 1387          case _FIOFFS:
 803 1388                  error = smbfs_fsync(vp, 0, cr, ct);
 804 1389                  break;
 805 1390  
 806 1391                  /*
 807 1392                   * The following two ioctls are used by bfu.
 808 1393                   * Silently ignore to avoid bfu errors.
 809 1394                   */
 810 1395          case _FIOGDIO:
 811 1396          case _FIOSDIO:
 812 1397                  error = 0;
 813 1398                  break;
 814 1399  
 815      -#ifdef NOT_YET  /* XXX - from the NFS code. */
     1400 +#if 0   /* Todo - SMB ioctl query regions */
     1401 +        case _FIO_SEEK_DATA:
     1402 +        case _FIO_SEEK_HOLE:
     1403 +#endif
     1404 +
 816 1405          case _FIODIRECTIO:
 817 1406                  error = smbfs_directio(vp, (int)arg, cr);
 818      -#endif
     1407 +                break;
 819 1408  
 820 1409                  /*
 821 1410                   * Allow get/set with "raw" security descriptor (SD) data.
 822 1411                   * Useful for testing, diagnosing idmap problems, etc.
 823 1412                   */
 824 1413          case SMBFSIO_GETSD:
 825 1414                  error = smbfs_acl_iocget(vp, arg, flag, cr);
 826 1415                  break;
 827 1416  
 828 1417          case SMBFSIO_SETSD:
↓ open down ↓ 13 lines elided ↑ open up ↑
 842 1431   * Return either cached or remote attributes. If get remote attr
 843 1432   * use them to check and invalidate caches, then cache the new attributes.
 844 1433   */
 845 1434  /* ARGSUSED */
 846 1435  static int
 847 1436  smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 848 1437          caller_context_t *ct)
 849 1438  {
 850 1439          smbnode_t *np;
 851 1440          smbmntinfo_t *smi;
     1441 +        int error;
 852 1442  
 853 1443          smi = VTOSMI(vp);
 854 1444  
 855 1445          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 856 1446                  return (EIO);
 857 1447  
 858 1448          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 859 1449                  return (EIO);
 860 1450  
 861 1451          /*
↓ open down ↓ 14 lines elided ↑ open up ↑
 876 1466                                  vap->va_size = np->r_size;
 877 1467                          if (vap->va_mask | AT_FSID)
 878 1468                                  vap->va_fsid = vp->v_vfsp->vfs_dev;
 879 1469                          if (vap->va_mask | AT_RDEV)
 880 1470                                  vap->va_rdev = vp->v_rdev;
 881 1471                          mutex_exit(&np->r_statelock);
 882 1472                          return (0);
 883 1473                  }
 884 1474          }
 885 1475  
     1476 +        /*
     1477 +         * Only need to flush pages if asking for the mtime
     1478 +         * and if there any dirty pages.
     1479 +         *
     1480 +         * Here NFS also checks for async writes (np->r_awcount)
     1481 +         */
     1482 +        if (vap->va_mask & AT_MTIME) {
     1483 +                if (vn_has_cached_data(vp) &&
     1484 +                    ((np->r_flags & RDIRTY) != 0)) {
     1485 +                        mutex_enter(&np->r_statelock);
     1486 +                        np->r_gcount++;
     1487 +                        mutex_exit(&np->r_statelock);
     1488 +                        error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
     1489 +                        mutex_enter(&np->r_statelock);
     1490 +                        if (error && (error == ENOSPC || error == EDQUOT)) {
     1491 +                                if (!np->r_error)
     1492 +                                        np->r_error = error;
     1493 +                        }
     1494 +                        if (--np->r_gcount == 0)
     1495 +                                cv_broadcast(&np->r_cv);
     1496 +                        mutex_exit(&np->r_statelock);
     1497 +                }
     1498 +        }
     1499 +
 886 1500          return (smbfsgetattr(vp, vap, cr));
 887 1501  }
 888 1502  
 889 1503  /* smbfsgetattr() in smbfs_client.c */
 890 1504  
 891 1505  /*ARGSUSED4*/
 892 1506  static int
 893 1507  smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 894 1508                  caller_context_t *ct)
 895 1509  {
↓ open down ↓ 50 lines elided ↑ open up ↑
 946 1560                          /*
 947 1561                           * It might be more correct to return the
 948 1562                           * error here, but that causes complaints
 949 1563                           * when root extracts a cpio archive, etc.
 950 1564                           * So ignore this error, and go ahead with
 951 1565                           * the rest of the setattr work.
 952 1566                           */
 953 1567                  }
 954 1568          }
 955 1569  
 956      -        return (smbfssetattr(vp, vap, flags, cr));
     1570 +        error = smbfssetattr(vp, vap, flags, cr);
     1571 +
     1572 +#ifdef  SMBFS_VNEVENT
     1573 +        if (error == 0 && (vap->va_mask & AT_SIZE) && vap->va_size == 0)
     1574 +                vnevent_truncate(vp, ct);
     1575 +#endif
     1576 +
     1577 +        return (error);
 957 1578  }
 958 1579  
 959 1580  /*
 960 1581   * Mostly from Darwin smbfs_setattr()
 961 1582   * but then modified a lot.
 962 1583   */
 963 1584  /* ARGSUSED */
 964 1585  static int
 965 1586  smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
 966 1587  {
↓ open down ↓ 17 lines elided ↑ open up ↑
 984 1605           */
 985 1606          if (vp->v_flag & V_XATTRDIR)
 986 1607                  return (0);
 987 1608          if (np->n_flag & N_XATTR) {
 988 1609                  if (mask & AT_TIMES)
 989 1610                          SMBVDEBUG("ignore set time on xattr\n");
 990 1611                  mask &= AT_SIZE;
 991 1612          }
 992 1613  
 993 1614          /*
     1615 +         * Only need to flush pages if there are any pages and
     1616 +         * if the file is marked as dirty in some fashion.  The
     1617 +         * file must be flushed so that we can accurately
     1618 +         * determine the size of the file and the cached data
     1619 +         * after the SETATTR returns.  A file is considered to
     1620 +         * be dirty if it is either marked with RDIRTY, has
     1621 +         * outstanding i/o's active, or is mmap'd.  In this
     1622 +         * last case, we can't tell whether there are dirty
     1623 +         * pages, so we flush just to be sure.
     1624 +         */
     1625 +        if (vn_has_cached_data(vp) &&
     1626 +            ((np->r_flags & RDIRTY) ||
     1627 +            np->r_count > 0 ||
     1628 +            np->r_mapcnt > 0)) {
     1629 +                ASSERT(vp->v_type != VCHR);
     1630 +                error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
     1631 +                if (error && (error == ENOSPC || error == EDQUOT)) {
     1632 +                        mutex_enter(&np->r_statelock);
     1633 +                        if (!np->r_error)
     1634 +                                np->r_error = error;
     1635 +                        mutex_exit(&np->r_statelock);
     1636 +                }
     1637 +        }
     1638 +
     1639 +        /*
 994 1640           * If our caller is trying to set multiple attributes, they
 995 1641           * can make no assumption about what order they are done in.
 996 1642           * Here we try to do them in order of decreasing likelihood
 997 1643           * of failure, just to minimize the chance we'll wind up
 998 1644           * with a partially complete request.
 999 1645           */
1000 1646  
1001 1647          /* Shared lock for (possible) n_fid use. */
1002 1648          if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1003 1649                  return (EINTR);
↓ open down ↓ 41 lines elided ↑ open up ↑
1045 1691           * If the server supports the UNIX extensions, right here is where
1046 1692           * we'd support changes to uid, gid, mode, and possibly va_flags.
1047 1693           * For now we claim to have made any such changes.
1048 1694           */
1049 1695  
1050 1696          if (mask & AT_SIZE) {
1051 1697                  /*
1052 1698                   * If the new file size is less than what the client sees as
1053 1699                   * the file size, then just change the size and invalidate
1054 1700                   * the pages.
1055      -                 * I am commenting this code at present because the function
1056      -                 * smbfs_putapage() is not yet implemented.
1057 1701                   */
1058 1702  
1059 1703                  /*
1060 1704                   * Set the file size to vap->va_size.
1061 1705                   */
1062 1706                  ASSERT(have_fid);
1063 1707                  error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1064 1708                  if (error) {
1065 1709                          SMBVDEBUG("setsize error %d file %s\n",
1066 1710                              error, np->n_rpath);
1067 1711                  } else {
1068 1712                          /*
1069 1713                           * Darwin had code here to zero-extend.
1070 1714                           * Tests indicate the server will zero-fill,
1071      -                         * so looks like we don't need to do this.
1072      -                         * Good thing, as this could take forever.
1073      -                         *
1074      -                         * XXX: Reportedly, writing one byte of zero
1075      -                         * at the end offset avoids problems here.
     1715 +                         * so looks like we don't need to do that.
1076 1716                           */
1077 1717                          mutex_enter(&np->r_statelock);
1078 1718                          np->r_size = vap->va_size;
1079 1719                          mutex_exit(&np->r_statelock);
1080 1720                          modified = 1;
1081 1721                  }
1082 1722          }
1083 1723  
1084 1724          /*
1085      -         * XXX: When Solaris has create_time, set that too.
1086      -         * Note: create_time is different from ctime.
     1725 +         * Todo: Implement setting create_time (which is
     1726 +         * different from ctime).
1087 1727           */
1088 1728          mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1089 1729          atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1090 1730  
1091 1731          if (dosattr || mtime || atime) {
1092 1732                  /*
1093 1733                   * Always use the handle-based set attr call now.
1094 1734                   */
1095 1735                  ASSERT(have_fid);
1096 1736                  error = smbfs_smb_setfattr(np, fid,
1097 1737                      dosattr, mtime, atime, &scred);
1098 1738                  if (error) {
1099 1739                          SMBVDEBUG("set times error %d file %s\n",
1100 1740                              error, np->n_rpath);
1101 1741                  } else {
1102 1742                          modified = 1;
1103 1743                  }
1104 1744          }
1105 1745  
1106 1746  out:
1107      -        if (modified) {
1108      -                /*
1109      -                 * Invalidate attribute cache in case the server
1110      -                 * doesn't set exactly the attributes we asked.
1111      -                 */
1112      -                smbfs_attrcache_remove(np);
1113      -        }
1114      -
1115 1747          if (have_fid) {
1116 1748                  cerror = smbfs_smb_tmpclose(np, fid, &scred);
1117 1749                  if (cerror)
1118 1750                          SMBVDEBUG("error %d closing %s\n",
1119 1751                              cerror, np->n_rpath);
1120 1752          }
1121 1753  
1122 1754          smb_credrele(&scred);
1123 1755          smbfs_rw_exit(&np->r_lkserlock);
1124 1756  
     1757 +        if (modified) {
     1758 +                /*
     1759 +                 * Invalidate attribute cache in case the server
     1760 +                 * doesn't set exactly the attributes we asked.
     1761 +                 */
     1762 +                smbfs_attrcache_remove(np);
     1763 +
     1764 +                /*
     1765 +                 * If changing the size of the file, invalidate
     1766 +                 * any local cached data which is no longer part
     1767 +                 * of the file.  We also possibly invalidate the
     1768 +                 * last page in the file.  We could use
     1769 +                 * pvn_vpzero(), but this would mark the page as
     1770 +                 * modified and require it to be written back to
     1771 +                 * the server for no particularly good reason.
     1772 +                 * This way, if we access it, then we bring it
     1773 +                 * back in.  A read should be cheaper than a
     1774 +                 * write.
     1775 +                 */
     1776 +                if (mask & AT_SIZE) {
     1777 +                        smbfs_invalidate_pages(vp,
     1778 +                            (vap->va_size & PAGEMASK), cr);
     1779 +                }
     1780 +        }
     1781 +
1125 1782          return (error);
1126 1783  }
1127 1784  
1128 1785  /*
1129 1786   * Helper function for extensible system attributes (PSARC 2007/315)
1130 1787   * Compute the DOS attribute word to pass to _setfattr (see above).
1131 1788   * This returns zero IFF no change is being made to attributes.
1132 1789   * Otherwise return the new attributes or SMB_EFA_NORMAL.
1133 1790   */
1134 1791  static uint32_t
↓ open down ↓ 66 lines elided ↑ open up ↑
1201 1858   * With this model, there is a case where we need the
1202 1859   * ability to do an access check before we have the
1203 1860   * vnode for an object.  This function takes advantage
1204 1861   * of the fact that the uid/gid/mode is per mount, and
1205 1862   * avoids the need for a vnode.
1206 1863   *
1207 1864   * We still (sort of) need a vnode when we call
1208 1865   * secpolicy_vnode_access, but that only uses
1209 1866   * the vtype field, so we can use a pair of fake
1210 1867   * vnodes that have only v_type filled in.
1211      - *
1212      - * XXX: Later, add a new secpolicy_vtype_access()
1213      - * that takes the vtype instead of a vnode, and
1214      - * get rid of the tmpl_vxxx fake vnodes below.
1215 1868   */
1216 1869  static int
1217 1870  smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1218 1871  {
1219 1872          /* See the secpolicy call below. */
1220 1873          static const vnode_t tmpl_vdir = { .v_type = VDIR };
1221 1874          static const vnode_t tmpl_vreg = { .v_type = VREG };
1222 1875          vattr_t         va;
1223 1876          vnode_t         *tvp;
1224 1877          struct smbmntinfo *smi = VFTOSMI(vfsp);
1225 1878          int shift = 0;
1226 1879  
1227 1880          /*
1228 1881           * Build our (fabricated) vnode attributes.
1229      -         * XXX: Could make these templates in the
1230      -         * per-mount struct and use them here.
1231 1882           */
1232 1883          bzero(&va, sizeof (va));
1233 1884          va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1234 1885          va.va_type = vtype;
1235 1886          va.va_mode = (vtype == VDIR) ?
1236 1887              smi->smi_dmode : smi->smi_fmode;
1237 1888          va.va_uid = smi->smi_uid;
1238 1889          va.va_gid = smi->smi_gid;
1239 1890  
1240 1891          /*
↓ open down ↓ 4 lines elided ↑ open up ↑
1245 1896           * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1246 1897           */
1247 1898          if ((mode & VWRITE) &&
1248 1899              (vfsp->vfs_flag & VFS_RDONLY) &&
1249 1900              !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1250 1901                  return (EROFS);
1251 1902  
1252 1903          /*
1253 1904           * Disallow attempts to access mandatory lock files.
1254 1905           * Similarly, expand MANDLOCK here.
1255      -         * XXX: not sure we need this.
1256 1906           */
1257 1907          if ((mode & (VWRITE | VREAD | VEXEC)) &&
1258 1908              va.va_type == VREG && MANDMODE(va.va_mode))
1259 1909                  return (EACCES);
1260 1910  
1261 1911          /*
1262 1912           * Access check is based on only
1263 1913           * one of owner, group, public.
1264 1914           * If not owner, then check group.
1265 1915           * If not a member of the group,
↓ open down ↓ 49 lines elided ↑ open up ↑
1315 1965          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1316 1966                  return (EIO);
1317 1967  
1318 1968          if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1319 1969                  return (EIO);
1320 1970  
1321 1971          return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1322 1972  }
1323 1973  
1324 1974  
     1975 +/* ARGSUSED */
     1976 +static int
     1977 +smbfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
     1978 +{
     1979 +        /* Not yet... */
     1980 +        return (ENOSYS);
     1981 +}
     1982 +
     1983 +
1325 1984  /*
1326 1985   * Flush local dirty pages to stable storage on the server.
1327 1986   *
1328 1987   * If FNODSYNC is specified, then there is nothing to do because
1329 1988   * metadata changes are not cached on the client before being
1330 1989   * sent to the server.
1331 1990   */
1332 1991  /* ARGSUSED */
1333 1992  static int
1334 1993  smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
↓ open down ↓ 11 lines elided ↑ open up ↑
1346 2005  
1347 2006          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1348 2007                  return (EIO);
1349 2008  
1350 2009          if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1351 2010                  return (0);
1352 2011  
1353 2012          if ((syncflag & (FSYNC|FDSYNC)) == 0)
1354 2013                  return (0);
1355 2014  
     2015 +        error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
     2016 +        if (error)
     2017 +                return (error);
     2018 +
1356 2019          /* Shared lock for n_fid use in _flush */
1357 2020          if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1358 2021                  return (EINTR);
1359 2022          smb_credinit(&scred, cr);
1360 2023  
1361 2024          error = smbfs_smb_flush(np, &scred);
1362 2025  
1363 2026          smb_credrele(&scred);
1364 2027          smbfs_rw_exit(&np->r_lkserlock);
1365 2028  
1366 2029          return (error);
1367 2030  }
1368 2031  
1369 2032  /*
1370 2033   * Last reference to vnode went away.
1371 2034   */
1372 2035  /* ARGSUSED */
1373 2036  static void
1374 2037  smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1375 2038  {
1376      -        smbnode_t       *np;
1377 2039          struct smb_cred scred;
     2040 +        smbnode_t       *np = VTOSMB(vp);
     2041 +        int error;
1378 2042  
1379 2043          /*
1380 2044           * Don't "bail out" for VFS_UNMOUNTED here,
1381 2045           * as we want to do cleanup, etc.
1382 2046           * See also pcfs_inactive
1383 2047           */
1384 2048  
1385      -        np = VTOSMB(vp);
1386      -
1387 2049          /*
1388 2050           * If this is coming from the wrong zone, we let someone in the right
1389 2051           * zone take care of it asynchronously.  We can get here due to
1390 2052           * VN_RELE() being called from pageout() or fsflush().  This call may
1391 2053           * potentially turn into an expensive no-op if, for instance, v_count
1392 2054           * gets incremented in the meantime, but it's still correct.
1393 2055           */
1394 2056  
1395 2057          /*
     2058 +         * From NFS:rinactive()
     2059 +         *
     2060 +         * Before freeing anything, wait until all asynchronous
     2061 +         * activity is done on this rnode.  This will allow all
     2062 +         * asynchronous read ahead and write behind i/o's to
     2063 +         * finish.
     2064 +         */
     2065 +        mutex_enter(&np->r_statelock);
     2066 +        while (np->r_count > 0)
     2067 +                cv_wait(&np->r_cv, &np->r_statelock);
     2068 +        mutex_exit(&np->r_statelock);
     2069 +
     2070 +        /*
     2071 +         * Flush and invalidate all pages associated with the vnode.
     2072 +         */
     2073 +        if (vn_has_cached_data(vp)) {
     2074 +                if ((np->r_flags & RDIRTY) && !np->r_error) {
     2075 +                        error = smbfs_putpage(vp, (u_offset_t)0, 0, 0, cr, ct);
     2076 +                        if (error && (error == ENOSPC || error == EDQUOT)) {
     2077 +                                mutex_enter(&np->r_statelock);
     2078 +                                if (!np->r_error)
     2079 +                                        np->r_error = error;
     2080 +                                mutex_exit(&np->r_statelock);
     2081 +                        }
     2082 +                }
     2083 +                smbfs_invalidate_pages(vp, (u_offset_t)0, cr);
     2084 +        }
     2085 +        /*
     2086 +         * This vnode should have lost all cached data.
     2087 +         */
     2088 +        ASSERT(vn_has_cached_data(vp) == 0);
     2089 +
     2090 +        /*
1396 2091           * Defend against the possibility that higher-level callers
1397 2092           * might not correctly balance open and close calls.  If we
1398 2093           * get here with open references remaining, it means there
1399 2094           * was a missing VOP_CLOSE somewhere.  If that happens, do
1400 2095           * the close here so we don't "leak" FIDs on the server.
1401 2096           *
1402 2097           * Exclusive lock for modifying n_fid stuff.
1403 2098           * Don't want this one ever interruptible.
1404 2099           */
1405 2100          (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
↓ open down ↓ 127 lines elided ↑ open up ↑
1533 2228          vcp = SSTOVC(smi->smi_share);
1534 2229  
1535 2230          /* XXX: Should compute this once and store it in smbmntinfo_t */
1536 2231          supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1537 2232  #else
1538 2233          supplen = 255;
1539 2234  #endif
1540 2235  
1541 2236          /*
1542 2237           * RWlock must be held, either reader or writer.
1543      -         * XXX: Can we check without looking directly
1544      -         * inside the struct smbfs_rwlock_t?
1545 2238           */
1546 2239          ASSERT(dnp->r_rwlock.count != 0);
1547 2240  
1548 2241          /*
1549 2242           * If lookup is for "", just return dvp.
1550 2243           * No need to perform any access checks.
1551 2244           */
1552 2245          if (nmlen == 0) {
1553 2246                  VN_HOLD(dvp);
1554 2247                  *vpp = dvp;
↓ open down ↓ 26 lines elided ↑ open up ↑
1581 2274          /*
1582 2275           * Now some sanity checks on the name.
1583 2276           * First check the length.
1584 2277           */
1585 2278          if (nmlen > supplen)
1586 2279                  return (ENAMETOOLONG);
1587 2280  
1588 2281          /*
1589 2282           * Avoid surprises with characters that are
1590 2283           * illegal in Windows file names.
1591      -         * Todo: CATIA mappings  XXX
     2284 +         * Todo: CATIA mappings?
1592 2285           */
1593 2286          ill = illegal_chars;
1594 2287          if (dnp->n_flag & N_XATTR)
1595 2288                  ill++; /* allow colon */
1596 2289          if (strpbrk(nm, ill))
1597 2290                  return (EINVAL);
1598 2291  
1599 2292          /*
1600 2293           * Special handling for lookup of ".."
1601 2294           *
↓ open down ↓ 200 lines elided ↑ open up ↑
1802 2495           * Success!
1803 2496           * Caller gets hold from smbfs_node_findcreate
1804 2497           */
1805 2498  #ifdef DEBUG
1806 2499          smbfs_lookup_cache_hits++;
1807 2500  #endif
1808 2501          *vpp = vp;
1809 2502          return (0);
1810 2503  }
1811 2504  
     2505 +
1812 2506  /*
1813 2507   * XXX
1814 2508   * vsecattr_t is new to build 77, and we need to eventually support
1815 2509   * it in order to create an ACL when an object is created.
1816 2510   *
1817 2511   * This op should support the new FIGNORECASE flag for case-insensitive
1818 2512   * lookups, per PSARC 2007/244.
1819 2513   */
1820 2514  /* ARGSUSED */
1821 2515  static int
1822 2516  smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1823 2517          int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1824 2518          vsecattr_t *vsecp)
1825 2519  {
1826 2520          int             error;
1827 2521          int             cerror;
1828 2522          vfs_t           *vfsp;
1829 2523          vnode_t         *vp;
1830      -#ifdef NOT_YET
1831 2524          smbnode_t       *np;
1832      -#endif
1833 2525          smbnode_t       *dnp;
1834 2526          smbmntinfo_t    *smi;
1835 2527          struct vattr    vattr;
1836 2528          struct smbfattr fattr;
1837 2529          struct smb_cred scred;
1838 2530          const char *name = (const char *)nm;
1839 2531          int             nmlen = strlen(nm);
1840 2532          uint32_t        disp;
1841 2533          uint16_t        fid;
1842 2534          int             xattr;
↓ open down ↓ 5 lines elided ↑ open up ↑
1848 2540  
1849 2541          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1850 2542                  return (EPERM);
1851 2543  
1852 2544          if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1853 2545                  return (EIO);
1854 2546  
1855 2547          /*
1856 2548           * Note: this may break mknod(2) calls to create a directory,
1857 2549           * but that's obscure use.  Some other filesystems do this.
1858      -         * XXX: Later, redirect VDIR type here to _mkdir.
     2550 +         * Todo: redirect VDIR type here to _mkdir.
1859 2551           */
1860 2552          if (va->va_type != VREG)
1861 2553                  return (EINVAL);
1862 2554  
1863 2555          /*
1864 2556           * If the pathname is "", just use dvp, no checks.
1865 2557           * Do this outside of the rwlock (like zfs).
1866 2558           */
1867 2559          if (nmlen == 0) {
1868 2560                  VN_HOLD(dvp);
↓ open down ↓ 44 lines elided ↑ open up ↑
1913 2605                   */
1914 2606                  error = smbfs_access(vp, mode, 0, cr, ct);
1915 2607                  if (error) {
1916 2608                          VN_RELE(vp);
1917 2609                          goto out;
1918 2610                  }
1919 2611  
1920 2612                  /*
1921 2613                   * Truncate (if requested).
1922 2614                   */
1923      -                if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
     2615 +                if ((vattr.va_mask & AT_SIZE) && vp->v_type == VREG) {
     2616 +                        np = VTOSMB(vp);
     2617 +                        /*
     2618 +                         * Check here for large file truncation by
     2619 +                         * LF-unaware process, like ufs_create().
     2620 +                         */
     2621 +                        if (!(lfaware & FOFFMAX)) {
     2622 +                                mutex_enter(&np->r_statelock);
     2623 +                                if (np->r_size > MAXOFF32_T)
     2624 +                                        error = EOVERFLOW;
     2625 +                                mutex_exit(&np->r_statelock);
     2626 +                        }
     2627 +                        if (error) {
     2628 +                                VN_RELE(vp);
     2629 +                                goto out;
     2630 +                        }
1924 2631                          vattr.va_mask = AT_SIZE;
1925 2632                          error = smbfssetattr(vp, &vattr, 0, cr);
1926 2633                          if (error) {
1927 2634                                  VN_RELE(vp);
1928 2635                                  goto out;
1929 2636                          }
     2637 +#ifdef  SMBFS_VNEVENT
     2638 +                        /* Existing file was truncated */
     2639 +                        vnevent_create(vp, ct);
     2640 +#endif
     2641 +                        /* invalidate pages done in smbfssetattr() */
1930 2642                  }
1931 2643                  /* Success! */
1932      -#ifdef NOT_YET
1933      -                vnevent_create(vp, ct);
1934      -#endif
1935 2644                  *vpp = vp;
1936 2645                  goto out;
1937 2646          }
1938 2647  
1939 2648          /*
1940 2649           * The file did not exist.  Need VWRITE in the directory.
1941 2650           */
1942 2651          error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1943 2652          if (error)
1944 2653                  goto out;
↓ open down ↓ 28 lines elided ↑ open up ↑
1973 2682                          disp = NTCREATEX_DISP_OPEN_IF;
1974 2683          }
1975 2684          xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1976 2685          error = smbfs_smb_create(dnp,
1977 2686              name, nmlen, xattr,
1978 2687              disp, &scred, &fid);
1979 2688          if (error)
1980 2689                  goto out;
1981 2690  
1982 2691          /*
1983      -         * XXX: Missing some code here to deal with
1984      -         * the case where we opened an existing file,
1985      -         * it's size is larger than 32-bits, and we're
1986      -         * setting the size from a process that's not
1987      -         * aware of large file offsets.  i.e.
1988      -         * from the NFS3 code:
1989      -         */
1990      -#if NOT_YET /* XXX */
1991      -        if ((vattr.va_mask & AT_SIZE) &&
1992      -            vp->v_type == VREG) {
1993      -                np = VTOSMB(vp);
1994      -                /*
1995      -                 * Check here for large file handled
1996      -                 * by LF-unaware process (as
1997      -                 * ufs_create() does)
1998      -                 */
1999      -                if (!(lfaware & FOFFMAX)) {
2000      -                        mutex_enter(&np->r_statelock);
2001      -                        if (np->r_size > MAXOFF32_T)
2002      -                                error = EOVERFLOW;
2003      -                        mutex_exit(&np->r_statelock);
2004      -                }
2005      -                if (!error) {
2006      -                        vattr.va_mask = AT_SIZE;
2007      -                        error = smbfssetattr(vp,
2008      -                            &vattr, 0, cr);
2009      -                }
2010      -        }
2011      -#endif /* XXX */
2012      -        /*
2013 2692           * Should use the fid to get/set the size
2014 2693           * while we have it opened here.  See above.
2015 2694           */
2016 2695  
2017 2696          cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
2018 2697          if (cerror)
2019 2698                  SMBVDEBUG("error %d closing %s\\%s\n",
2020 2699                      cerror, dnp->n_rpath, name);
2021 2700  
2022 2701          /*
↓ open down ↓ 9 lines elided ↑ open up ↑
2032 2711          if (error)
2033 2712                  goto out;
2034 2713  
2035 2714          /* update attr and directory cache */
2036 2715          smbfs_attr_touchdir(dnp);
2037 2716  
2038 2717          error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2039 2718          if (error)
2040 2719                  goto out;
2041 2720  
2042      -        /* XXX invalidate pages if we truncated? */
2043      -
2044 2721          /* Success! */
2045 2722          *vpp = vp;
2046 2723          error = 0;
2047 2724  
2048 2725  out:
2049 2726          smb_credrele(&scred);
2050 2727          smbfs_rw_exit(&dnp->r_rwlock);
2051 2728          if (name != nm)
2052 2729                  smbfs_name_free(name, nmlen);
2053 2730          return (error);
↓ open down ↓ 85 lines elided ↑ open up ↑
2139 2816  
2140 2817          /*
2141 2818           * The dvp RWlock must be held as writer.
2142 2819           */
2143 2820          ASSERT(dnp->r_rwlock.owner == curthread);
2144 2821  
2145 2822          /* Never allow link/unlink directories on SMB. */
2146 2823          if (vp->v_type == VDIR)
2147 2824                  return (EPERM);
2148 2825  
     2826 +        /*
     2827 +         * We need to flush any dirty pages which happen to
     2828 +         * be hanging around before removing the file.  This
     2829 +         * shouldn't happen very often and mostly on file
     2830 +         * systems mounted "nocto".
     2831 +         */
     2832 +        if (vn_has_cached_data(vp) &&
     2833 +            ((np->r_flags & RDIRTY) || np->r_count > 0)) {
     2834 +                error = smbfs_putpage(vp, (offset_t)0, 0, 0,
     2835 +                    scred->scr_cred, NULL);
     2836 +                if (error && (error == ENOSPC || error == EDQUOT)) {
     2837 +                        mutex_enter(&np->r_statelock);
     2838 +                        if (!np->r_error)
     2839 +                                np->r_error = error;
     2840 +                        mutex_exit(&np->r_statelock);
     2841 +                }
     2842 +        }
     2843 +
2149 2844          /* Shared lock for n_fid use in smbfs_smb_setdisp etc. */
2150 2845          if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
2151 2846                  return (EINTR);
2152 2847  
2153      -        /* Force lookup to go OtW */
2154      -        smbfs_attrcache_remove(np);
2155      -
2156 2848          /*
2157 2849           * Get a file handle with delete access.
2158 2850           * Close this FID before return.
2159 2851           */
2160 2852          error = smbfs_smb_tmpopen(np, STD_RIGHT_DELETE_ACCESS,
2161 2853              scred, &fid);
2162 2854          if (error) {
2163 2855                  SMBVDEBUG("error %d opening %s\n",
2164 2856                      error, np->n_rpath);
2165 2857                  goto out;
↓ open down ↓ 3 lines elided ↑ open up ↑
2169 2861          /*
2170 2862           * If we have the file open, try to rename it to a temporary name.
2171 2863           * If we can't rename, continue on and try setting DoC anyway.
2172 2864           */
2173 2865          if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2174 2866                  tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2175 2867                  tnlen = smbfs_newname(tmpname, MAXNAMELEN);
2176 2868                  error = smbfs_smb_t2rename(np, tmpname, tnlen, scred, fid, 0);
2177 2869                  if (error != 0) {
2178 2870                          SMBVDEBUG("error %d renaming %s -> %s\n",
2179      -                                  error, np->n_rpath, tmpname);
     2871 +                            error, np->n_rpath, tmpname);
2180 2872                          /* Keep going without the rename. */
2181 2873                  } else {
2182 2874                          renamed = B_TRUE;
2183 2875                  }
2184 2876          }
2185 2877  
2186 2878          /*
2187 2879           * Mark the file as delete-on-close.  If we can't,
2188 2880           * undo what we did and err out.
2189 2881           */
↓ open down ↓ 10 lines elided ↑ open up ↑
2200 2892                  if (renamed) {
2201 2893                          char *oldname;
2202 2894                          int oldnlen;
2203 2895                          int err2;
2204 2896  
2205 2897                          oldname = np->n_rpath + (dnp->n_rplen + 1);
2206 2898                          oldnlen = np->n_rplen - (dnp->n_rplen + 1);
2207 2899                          err2 = smbfs_smb_t2rename(np, oldname, oldnlen,
2208 2900                              scred, fid, 0);
2209 2901                          SMBVDEBUG("error %d un-renaming %s -> %s\n",
2210      -                          err2, tmpname, np->n_rpath);
     2902 +                            err2, tmpname, np->n_rpath);
2211 2903                  }
2212 2904                  error = EBUSY;
2213 2905                  goto out;
2214 2906          }
2215 2907          /* Done! */
2216 2908          smbfs_attrcache_prune(np);
2217 2909  
     2910 +#ifdef  SMBFS_VNEVENT
     2911 +        vnevent_remove(vp, dvp, nm, ct);
     2912 +#endif
     2913 +
2218 2914  out:
2219 2915          if (tmpname != NULL)
2220 2916                  kmem_free(tmpname, MAXNAMELEN);
2221 2917  
2222 2918          if (have_fid)
2223 2919                  (void) smbfs_smb_tmpclose(np, fid, scred);
2224 2920          smbfs_rw_exit(&np->r_lkserlock);
2225 2921  
2226 2922          if (error == 0) {
2227 2923                  /* Keep lookup from finding this node anymore. */
2228 2924                  smbfs_rmhash(np);
2229 2925          }
2230 2926  
2231 2927          return (error);
2232 2928  }
2233 2929  
2234 2930  
     2931 +/* ARGSUSED */
     2932 +static int
     2933 +smbfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
     2934 +        caller_context_t *ct, int flags)
     2935 +{
     2936 +        /* Not yet... */
     2937 +        return (ENOSYS);
     2938 +}
     2939 +
     2940 +
2235 2941  /*
2236 2942   * XXX
2237 2943   * This op should support the new FIGNORECASE flag for case-insensitive
2238 2944   * lookups, per PSARC 2007/244.
2239 2945   */
2240 2946  /* ARGSUSED */
2241 2947  static int
2242 2948  smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2243 2949          caller_context_t *ct, int flags)
2244 2950  {
↓ open down ↓ 172 lines elided ↑ open up ↑
2417 3123                   * OK, removed the target file.  Continue as if
2418 3124                   * lookup target had failed (nvp == NULL).
2419 3125                   */
2420 3126                  vn_vfsunlock(nvp);
2421 3127                  nvp_locked = 0;
2422 3128                  VN_RELE(nvp);
2423 3129                  nvp = NULL;
2424 3130          } /* nvp */
2425 3131  
2426 3132          smbfs_attrcache_remove(onp);
2427      -
2428 3133          error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), scred);
2429 3134  
2430 3135          /*
2431 3136           * If the old name should no longer exist,
2432 3137           * discard any cached attributes under it.
2433 3138           */
2434      -        if (error == 0)
     3139 +        if (error == 0) {
2435 3140                  smbfs_attrcache_prune(onp);
     3141 +                /* SMBFS_VNEVENT... */
     3142 +        }
2436 3143  
2437 3144  out:
2438 3145          if (nvp) {
2439 3146                  if (nvp_locked)
2440 3147                          vn_vfsunlock(nvp);
2441 3148                  VN_RELE(nvp);
2442 3149          }
2443 3150  
2444 3151          return (error);
2445 3152  }
↓ open down ↓ 32 lines elided ↑ open up ↑
2478 3185  
2479 3186          /* Only plain files are allowed in V_XATTRDIR. */
2480 3187          if (dvp->v_flag & V_XATTRDIR)
2481 3188                  return (EINVAL);
2482 3189  
2483 3190          if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2484 3191                  return (EINTR);
2485 3192          smb_credinit(&scred, cr);
2486 3193  
2487 3194          /*
2488      -         * XXX: Do we need r_lkserlock too?
2489      -         * No use of any shared fid or fctx...
2490      -         */
2491      -
2492      -        /*
2493 3195           * Require write access in the containing directory.
2494 3196           */
2495 3197          error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2496 3198          if (error)
2497 3199                  goto out;
2498 3200  
2499 3201          error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2500 3202          if (error)
2501 3203                  goto out;
2502 3204  
↓ open down ↓ 122 lines elided ↑ open up ↑
2625 3327          }
2626 3328          smb_credrele(&scred);
2627 3329          smbfs_rw_exit(&dnp->r_rwlock);
2628 3330  
2629 3331          return (error);
2630 3332  }
2631 3333  
2632 3334  
2633 3335  /* ARGSUSED */
2634 3336  static int
     3337 +smbfs_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
     3338 +        caller_context_t *ct, int flags)
     3339 +{
     3340 +        /* Not yet... */
     3341 +        return (ENOSYS);
     3342 +}
     3343 +
     3344 +
     3345 +/* ARGSUSED */
     3346 +static int
2635 3347  smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2636 3348          caller_context_t *ct, int flags)
2637 3349  {
2638 3350          struct smbnode  *np = VTOSMB(vp);
2639 3351          int             error = 0;
2640 3352          smbmntinfo_t    *smi;
2641 3353  
2642 3354          smi = VTOSMI(vp);
2643 3355  
2644 3356          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
↓ open down ↓ 5 lines elided ↑ open up ↑
2650 3362          /*
2651 3363           * Require read access in the directory.
2652 3364           */
2653 3365          error = smbfs_access(vp, VREAD, 0, cr, ct);
2654 3366          if (error)
2655 3367                  return (error);
2656 3368  
2657 3369          ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2658 3370  
2659 3371          /*
2660      -         * XXX: Todo readdir cache here
2661      -         * Note: NFS code is just below this.
     3372 +         * Todo readdir cache here
2662 3373           *
2663 3374           * I am serializing the entire readdir opreation
2664 3375           * now since we have not yet implemented readdir
2665 3376           * cache. This fix needs to be revisited once
2666 3377           * we implement readdir cache.
2667 3378           */
2668 3379          if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2669 3380                  return (EINTR);
2670 3381  
2671 3382          error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
↓ open down ↓ 213 lines elided ↑ open up ↑
2885 3596                  uio->uio_resid = save_resid;
2886 3597          }
2887 3598          SMBVDEBUG("out: offset=%d, resid=%d\n",
2888 3599              (int)uio->uio_offset, (int)uio->uio_resid);
2889 3600  
2890 3601          kmem_free(dp, dbufsiz);
2891 3602          smb_credrele(&scred);
2892 3603          return (error);
2893 3604  }
2894 3605  
     3606 +/*
     3607 + * Here NFS has: nfs3_bio
     3608 + * See smbfs_bio above.
     3609 + */
2895 3610  
     3611 +/* ARGSUSED */
     3612 +static int
     3613 +smbfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
     3614 +{
     3615 +        return (ENOSYS);
     3616 +}
     3617 +
     3618 +
2896 3619  /*
2897 3620   * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2898 3621   * are optional functions that are called by:
2899 3622   *    getdents, before/after VOP_READDIR
2900 3623   *    pread, before/after ... VOP_READ
2901 3624   *    pwrite, before/after ... VOP_WRITE
2902 3625   *    (other places)
2903 3626   *
2904 3627   * Careful here: None of the above check for any
2905 3628   * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
↓ open down ↓ 53 lines elided ↑ open up ↑
2959 3682          if (vp->v_type == VDIR)
2960 3683                  return (0);
2961 3684  
2962 3685          /* Like NFS3, just check for 63-bit overflow. */
2963 3686          if (*noffp < 0)
2964 3687                  return (EINVAL);
2965 3688  
2966 3689          return (0);
2967 3690  }
2968 3691  
     3692 +/* mmap support ******************************************************** */
2969 3693  
     3694 +#ifdef DEBUG
     3695 +static int smbfs_lostpage = 0;  /* number of times we lost original page */
     3696 +#endif
     3697 +
2970 3698  /*
     3699 + * Return all the pages from [off..off+len) in file
     3700 + * Like nfs3_getpage
     3701 + */
     3702 +/* ARGSUSED */
     3703 +static int
     3704 +smbfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
     3705 +        page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
     3706 +        enum seg_rw rw, cred_t *cr, caller_context_t *ct)
     3707 +{
     3708 +        smbnode_t       *np;
     3709 +        smbmntinfo_t    *smi;
     3710 +        int             error;
     3711 +
     3712 +        np = VTOSMB(vp);
     3713 +        smi = VTOSMI(vp);
     3714 +
     3715 +        if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
     3716 +                return (EIO);
     3717 +
     3718 +        if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
     3719 +                return (EIO);
     3720 +
     3721 +        if (vp->v_flag & VNOMAP)
     3722 +                return (ENOSYS);
     3723 +
     3724 +        if (protp != NULL)
     3725 +                *protp = PROT_ALL;
     3726 +
     3727 +        /*
     3728 +         * Now valididate that the caches are up to date.
     3729 +         */
     3730 +        error = smbfs_validate_caches(vp, cr);
     3731 +        if (error)
     3732 +                return (error);
     3733 +
     3734 +retry:
     3735 +        mutex_enter(&np->r_statelock);
     3736 +
     3737 +        /*
     3738 +         * Don't create dirty pages faster than they
     3739 +         * can be cleaned ... (etc. see nfs)
     3740 +         *
     3741 +         * Here NFS also tests:
     3742 +         *  (mi->mi_max_threads != 0 &&
     3743 +         *  rp->r_awcount > 2 * mi->mi_max_threads)
     3744 +         */
     3745 +        if (rw == S_CREATE) {
     3746 +                while (np->r_gcount > 0)
     3747 +                        cv_wait(&np->r_cv, &np->r_statelock);
     3748 +        }
     3749 +
     3750 +        /*
     3751 +         * If we are getting called as a side effect of a write
     3752 +         * operation the local file size might not be extended yet.
     3753 +         * In this case we want to be able to return pages of zeroes.
     3754 +         */
     3755 +        if (off + len > np->r_size + PAGEOFFSET && seg != segkmap) {
     3756 +                mutex_exit(&np->r_statelock);
     3757 +                return (EFAULT);                /* beyond EOF */
     3758 +        }
     3759 +
     3760 +        mutex_exit(&np->r_statelock);
     3761 +
     3762 +        error = pvn_getpages(smbfs_getapage, vp, off, len, protp,
     3763 +            pl, plsz, seg, addr, rw, cr);
     3764 +
     3765 +        switch (error) {
     3766 +        case SMBFS_EOF:
     3767 +                smbfs_purge_caches(vp, cr);
     3768 +                goto retry;
     3769 +        case ESTALE:
     3770 +                /*
     3771 +                 * Here NFS has: PURGE_STALE_FH(error, vp, cr);
     3772 +                 * In-line here as we only use it once.
     3773 +                 */
     3774 +                mutex_enter(&np->r_statelock);
     3775 +                np->r_flags |= RSTALE;
     3776 +                if (!np->r_error)
     3777 +                        np->r_error = (error);
     3778 +                mutex_exit(&np->r_statelock);
     3779 +                if (vn_has_cached_data(vp))
     3780 +                        smbfs_invalidate_pages(vp, (u_offset_t)0, cr);
     3781 +                smbfs_purge_caches(vp, cr);
     3782 +                break;
     3783 +        default:
     3784 +                break;
     3785 +        }
     3786 +
     3787 +        return (error);
     3788 +}
     3789 +
     3790 +/*
     3791 + * Called from pvn_getpages to get a particular page.
     3792 + * Like nfs3_getapage
     3793 + */
     3794 +/* ARGSUSED */
     3795 +static int
     3796 +smbfs_getapage(vnode_t *vp, u_offset_t off, size_t len, uint_t *protp,
     3797 +        page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
     3798 +        enum seg_rw rw, cred_t *cr)
     3799 +{
     3800 +        smbnode_t       *np;
     3801 +        smbmntinfo_t   *smi;
     3802 +
     3803 +        uint_t          bsize;
     3804 +        struct buf      *bp;
     3805 +        page_t          *pp;
     3806 +        u_offset_t      lbn;
     3807 +        u_offset_t      io_off;
     3808 +        u_offset_t      blkoff;
     3809 +        size_t          io_len;
     3810 +        uint_t blksize;
     3811 +        int error;
     3812 +        /* int readahead; */
     3813 +        int readahead_issued = 0;
     3814 +        /* int ra_window; * readahead window */
     3815 +        page_t *pagefound;
     3816 +
     3817 +        np = VTOSMB(vp);
     3818 +        smi = VTOSMI(vp);
     3819 +
     3820 +        if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
     3821 +                return (EIO);
     3822 +
     3823 +        if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
     3824 +                return (EIO);
     3825 +
     3826 +        bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
     3827 +
     3828 +reread:
     3829 +        bp = NULL;
     3830 +        pp = NULL;
     3831 +        pagefound = NULL;
     3832 +
     3833 +        if (pl != NULL)
     3834 +                pl[0] = NULL;
     3835 +
     3836 +        error = 0;
     3837 +        lbn = off / bsize;
     3838 +        blkoff = lbn * bsize;
     3839 +
     3840 +        /*
     3841 +         * NFS queues up readahead work here.
     3842 +         */
     3843 +
     3844 +again:
     3845 +        if ((pagefound = page_exists(vp, off)) == NULL) {
     3846 +                if (pl == NULL) {
     3847 +                        (void) 0; /* Todo: smbfs_async_readahead(); */
     3848 +                } else if (rw == S_CREATE) {
     3849 +                        /*
     3850 +                         * Block for this page is not allocated, or the offset
     3851 +                         * is beyond the current allocation size, or we're
     3852 +                         * allocating a swap slot and the page was not found,
     3853 +                         * so allocate it and return a zero page.
     3854 +                         */
     3855 +                        if ((pp = page_create_va(vp, off,
     3856 +                            PAGESIZE, PG_WAIT, seg, addr)) == NULL)
     3857 +                                cmn_err(CE_PANIC, "smbfs_getapage: page_create");
     3858 +                        io_len = PAGESIZE;
     3859 +                        mutex_enter(&np->r_statelock);
     3860 +                        np->r_nextr = off + PAGESIZE;
     3861 +                        mutex_exit(&np->r_statelock);
     3862 +                } else {
     3863 +                        /*
     3864 +                         * Need to go to server to get a BLOCK, exception to
     3865 +                         * that being while reading at offset = 0 or doing
     3866 +                         * random i/o, in that case read only a PAGE.
     3867 +                         */
     3868 +                        mutex_enter(&np->r_statelock);
     3869 +                        if (blkoff < np->r_size &&
     3870 +                            blkoff + bsize >= np->r_size) {
     3871 +                                /*
     3872 +                                 * If only a block or less is left in
     3873 +                                 * the file, read all that is remaining.
     3874 +                                 */
     3875 +                                if (np->r_size <= off) {
     3876 +                                        /*
     3877 +                                         * Trying to access beyond EOF,
     3878 +                                         * set up to get at least one page.
     3879 +                                         */
     3880 +                                        blksize = off + PAGESIZE - blkoff;
     3881 +                                } else
     3882 +                                        blksize = np->r_size - blkoff;
     3883 +                        } else if ((off == 0) ||
     3884 +                            (off != np->r_nextr && !readahead_issued)) {
     3885 +                                blksize = PAGESIZE;
     3886 +                                blkoff = off; /* block = page here */
     3887 +                        } else
     3888 +                                blksize = bsize;
     3889 +                        mutex_exit(&np->r_statelock);
     3890 +
     3891 +                        pp = pvn_read_kluster(vp, off, seg, addr, &io_off,
     3892 +                            &io_len, blkoff, blksize, 0);
     3893 +
     3894 +                        /*
     3895 +                         * Some other thread has entered the page,
     3896 +                         * so just use it.
     3897 +                         */
     3898 +                        if (pp == NULL)
     3899 +                                goto again;
     3900 +
     3901 +                        /*
     3902 +                         * Now round the request size up to page boundaries.
     3903 +                         * This ensures that the entire page will be
     3904 +                         * initialized to zeroes if EOF is encountered.
     3905 +                         */
     3906 +                        io_len = ptob(btopr(io_len));
     3907 +
     3908 +                        bp = pageio_setup(pp, io_len, vp, B_READ);
     3909 +                        ASSERT(bp != NULL);
     3910 +
     3911 +                        /*
     3912 +                         * pageio_setup should have set b_addr to 0.  This
     3913 +                         * is correct since we want to do I/O on a page
     3914 +                         * boundary.  bp_mapin will use this addr to calculate
     3915 +                         * an offset, and then set b_addr to the kernel virtual
     3916 +                         * address it allocated for us.
     3917 +                         */
     3918 +                        ASSERT(bp->b_un.b_addr == 0);
     3919 +
     3920 +                        bp->b_edev = 0;
     3921 +                        bp->b_dev = 0;
     3922 +                        bp->b_lblkno = lbtodb(io_off);
     3923 +                        bp->b_file = vp;
     3924 +                        bp->b_offset = (offset_t)off;
     3925 +                        bp_mapin(bp);
     3926 +
     3927 +                        /*
     3928 +                         * If doing a write beyond what we believe is EOF,
     3929 +                         * don't bother trying to read the pages from the
     3930 +                         * server, we'll just zero the pages here.  We
     3931 +                         * don't check that the rw flag is S_WRITE here
     3932 +                         * because some implementations may attempt a
     3933 +                         * read access to the buffer before copying data.
     3934 +                         */
     3935 +                        mutex_enter(&np->r_statelock);
     3936 +                        if (io_off >= np->r_size && seg == segkmap) {
     3937 +                                mutex_exit(&np->r_statelock);
     3938 +                                bzero(bp->b_un.b_addr, io_len);
     3939 +                        } else {
     3940 +                                mutex_exit(&np->r_statelock);
     3941 +                                error = smbfs_bio(bp, 0, cr);
     3942 +                        }
     3943 +
     3944 +                        /*
     3945 +                         * Unmap the buffer before freeing it.
     3946 +                         */
     3947 +                        bp_mapout(bp);
     3948 +                        pageio_done(bp);
     3949 +
     3950 +                        /* Here NFS3 updates all pp->p_fsdata */
     3951 +
     3952 +                        if (error == SMBFS_EOF) {
     3953 +                                /*
     3954 +                                 * If doing a write system call just return
     3955 +                                 * zeroed pages, else user tried to get pages
     3956 +                                 * beyond EOF, return error.  We don't check
     3957 +                                 * that the rw flag is S_WRITE here because
     3958 +                                 * some implementations may attempt a read
     3959 +                                 * access to the buffer before copying data.
     3960 +                                 */
     3961 +                                if (seg == segkmap)
     3962 +                                        error = 0;
     3963 +                                else
     3964 +                                        error = EFAULT;
     3965 +                        }
     3966 +
     3967 +                        if (!readahead_issued && !error) {
     3968 +                                mutex_enter(&np->r_statelock);
     3969 +                                np->r_nextr = io_off + io_len;
     3970 +                                mutex_exit(&np->r_statelock);
     3971 +                        }
     3972 +                }
     3973 +        }
     3974 +
     3975 +        if (pl == NULL)
     3976 +                return (error);
     3977 +
     3978 +        if (error) {
     3979 +                if (pp != NULL)
     3980 +                        pvn_read_done(pp, B_ERROR);
     3981 +                return (error);
     3982 +        }
     3983 +
     3984 +        if (pagefound) {
     3985 +                se_t se = (rw == S_CREATE ? SE_EXCL : SE_SHARED);
     3986 +
     3987 +                /*
     3988 +                 * Page exists in the cache, acquire the appropriate lock.
     3989 +                 * If this fails, start all over again.
     3990 +                 */
     3991 +                if ((pp = page_lookup(vp, off, se)) == NULL) {
     3992 +#ifdef DEBUG
     3993 +                        smbfs_lostpage++;
     3994 +#endif
     3995 +                        goto reread;
     3996 +                }
     3997 +                pl[0] = pp;
     3998 +                pl[1] = NULL;
     3999 +                return (0);
     4000 +        }
     4001 +
     4002 +        if (pp != NULL)
     4003 +                pvn_plist_init(pp, pl, plsz, off, io_len, rw);
     4004 +
     4005 +        return (error);
     4006 +}
     4007 +
     4008 +/*
     4009 + * Here NFS has: nfs3_readahead
     4010 + * No read-ahead in smbfs yet.
     4011 + */
     4012 +
     4013 +/*
     4014 + * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
     4015 + * If len == 0, do from off to EOF.
     4016 + *
     4017 + * The normal cases should be len == 0 && off == 0 (entire vp list),
     4018 + * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
     4019 + * (from pageout).
     4020 + *
     4021 + * Like nfs3_putpage + nfs_putpages
     4022 + */
     4023 +/* ARGSUSED */
     4024 +static int
     4025 +smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
     4026 +        caller_context_t *ct)
     4027 +{
     4028 +        smbnode_t *np;
     4029 +        smbmntinfo_t *smi;
     4030 +        page_t *pp;
     4031 +        u_offset_t eoff;
     4032 +        u_offset_t io_off;
     4033 +        size_t io_len;
     4034 +        int error;
     4035 +        int rdirty;
     4036 +        int err;
     4037 +
     4038 +        np = VTOSMB(vp);
     4039 +        smi = VTOSMI(vp);
     4040 +
     4041 +        if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
     4042 +                return (EIO);
     4043 +
     4044 +        if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
     4045 +                return (EIO);
     4046 +
     4047 +        if (vp->v_flag & VNOMAP)
     4048 +                return (ENOSYS);
     4049 +
     4050 +        /* Here NFS does rp->r_count (++/--) stuff. */
     4051 +
     4052 +        /* Beginning of code from nfs_putpages. */
     4053 +
     4054 +        if (!vn_has_cached_data(vp))
     4055 +                return (0);
     4056 +
     4057 +        /*
     4058 +         * If ROUTOFSPACE is set, then all writes turn into B_INVAL
     4059 +         * writes.  B_FORCE is set to force the VM system to actually
     4060 +         * invalidate the pages, even if the i/o failed.  The pages
     4061 +         * need to get invalidated because they can't be written out
     4062 +         * because there isn't any space left on either the server's
     4063 +         * file system or in the user's disk quota.  The B_FREE bit
     4064 +         * is cleared to avoid confusion as to whether this is a
     4065 +         * request to place the page on the freelist or to destroy
     4066 +         * it.
     4067 +         */
     4068 +        if ((np->r_flags & ROUTOFSPACE) ||
     4069 +            (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED))
     4070 +                flags = (flags & ~B_FREE) | B_INVAL | B_FORCE;
     4071 +
     4072 +        if (len == 0) {
     4073 +                /*
     4074 +                 * If doing a full file synchronous operation, then clear
     4075 +                 * the RDIRTY bit.  If a page gets dirtied while the flush
     4076 +                 * is happening, then RDIRTY will get set again.  The
     4077 +                 * RDIRTY bit must get cleared before the flush so that
     4078 +                 * we don't lose this information.
     4079 +                 *
     4080 +                 * NFS has B_ASYNC vs sync stuff here.
     4081 +                 */
     4082 +                if (off == (u_offset_t)0 &&
     4083 +                    (np->r_flags & RDIRTY)) {
     4084 +                        mutex_enter(&np->r_statelock);
     4085 +                        rdirty = (np->r_flags & RDIRTY);
     4086 +                        np->r_flags &= ~RDIRTY;
     4087 +                        mutex_exit(&np->r_statelock);
     4088 +                } else
     4089 +                        rdirty = 0;
     4090 +
     4091 +                /*
     4092 +                 * Search the entire vp list for pages >= off, and flush
     4093 +                 * the dirty pages.
     4094 +                 */
     4095 +                error = pvn_vplist_dirty(vp, off, smbfs_putapage,
     4096 +                    flags, cr);
     4097 +
     4098 +                /*
     4099 +                 * If an error occurred and the file was marked as dirty
     4100 +                 * before and we aren't forcibly invalidating pages, then
     4101 +                 * reset the RDIRTY flag.
     4102 +                 */
     4103 +                if (error && rdirty &&
     4104 +                    (flags & (B_INVAL | B_FORCE)) != (B_INVAL | B_FORCE)) {
     4105 +                        mutex_enter(&np->r_statelock);
     4106 +                        np->r_flags |= RDIRTY;
     4107 +                        mutex_exit(&np->r_statelock);
     4108 +                }
     4109 +        } else {
     4110 +                /*
     4111 +                 * Do a range from [off...off + len) looking for pages
     4112 +                 * to deal with.
     4113 +                 */
     4114 +                error = 0;
     4115 +                io_len = 1; /* quiet warnings */
     4116 +                eoff = off + len;
     4117 +
     4118 +                for (io_off = off; io_off < eoff; io_off += io_len) {
     4119 +                        mutex_enter(&np->r_statelock);
     4120 +                        if (io_off >= np->r_size) {
     4121 +                                mutex_exit(&np->r_statelock);
     4122 +                                break;
     4123 +                        }
     4124 +                        mutex_exit(&np->r_statelock);
     4125 +                        /*
     4126 +                         * If we are not invalidating, synchronously
     4127 +                         * freeing or writing pages use the routine
     4128 +                         * page_lookup_nowait() to prevent reclaiming
     4129 +                         * them from the free list.
     4130 +                         */
     4131 +                        if ((flags & B_INVAL) || !(flags & B_ASYNC)) {
     4132 +                                pp = page_lookup(vp, io_off,
     4133 +                                    (flags & (B_INVAL | B_FREE)) ?
     4134 +                                    SE_EXCL : SE_SHARED);
     4135 +                        } else {
     4136 +                                pp = page_lookup_nowait(vp, io_off,
     4137 +                                    (flags & B_FREE) ? SE_EXCL : SE_SHARED);
     4138 +                        }
     4139 +
     4140 +                        if (pp == NULL || !pvn_getdirty(pp, flags))
     4141 +                                io_len = PAGESIZE;
     4142 +                        else {
     4143 +                                err = smbfs_putapage(vp, pp, &io_off,
     4144 +                                    &io_len, flags, cr);
     4145 +                                if (!error)
     4146 +                                        error = err;
     4147 +                                /*
     4148 +                                 * "io_off" and "io_len" are returned as
     4149 +                                 * the range of pages we actually wrote.
     4150 +                                 * This allows us to skip ahead more quickly
     4151 +                                 * since several pages may've been dealt
     4152 +                                 * with by this iteration of the loop.
     4153 +                                 */
     4154 +                        }
     4155 +                }
     4156 +        }
     4157 +
     4158 +        return (error);
     4159 +}
     4160 +
     4161 +/*
     4162 + * Write out a single page, possibly klustering adjacent dirty pages.
     4163 + *
     4164 + * Like nfs3_putapage / nfs3_sync_putapage
     4165 + */
     4166 +static int
     4167 +smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
     4168 +        int flags, cred_t *cr)
     4169 +{
     4170 +        smbnode_t *np;
     4171 +        u_offset_t io_off;
     4172 +        u_offset_t lbn_off;
     4173 +        u_offset_t lbn;
     4174 +        size_t io_len;
     4175 +        uint_t bsize;
     4176 +        int error;
     4177 +
     4178 +        np = VTOSMB(vp);
     4179 +
     4180 +        ASSERT(!vn_is_readonly(vp));
     4181 +
     4182 +        bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
     4183 +        lbn = pp->p_offset / bsize;
     4184 +        lbn_off = lbn * bsize;
     4185 +
     4186 +        /*
     4187 +         * Find a kluster that fits in one block, or in
     4188 +         * one page if pages are bigger than blocks.  If
     4189 +         * there is less file space allocated than a whole
     4190 +         * page, we'll shorten the i/o request below.
     4191 +         */
     4192 +        pp = pvn_write_kluster(vp, pp, &io_off, &io_len, lbn_off,
     4193 +            roundup(bsize, PAGESIZE), flags);
     4194 +
     4195 +        /*
     4196 +         * pvn_write_kluster shouldn't have returned a page with offset
     4197 +         * behind the original page we were given.  Verify that.
     4198 +         */
     4199 +        ASSERT((pp->p_offset / bsize) >= lbn);
     4200 +
     4201 +        /*
     4202 +         * Now pp will have the list of kept dirty pages marked for
     4203 +         * write back.  It will also handle invalidation and freeing
     4204 +         * of pages that are not dirty.  Check for page length rounding
     4205 +         * problems.
     4206 +         */
     4207 +        if (io_off + io_len > lbn_off + bsize) {
     4208 +                ASSERT((io_off + io_len) - (lbn_off + bsize) < PAGESIZE);
     4209 +                io_len = lbn_off + bsize - io_off;
     4210 +        }
     4211 +        /*
     4212 +         * The RMODINPROGRESS flag makes sure that smbfs_bio() sees a
     4213 +         * consistent value of r_size. RMODINPROGRESS is set in writerp().
     4214 +         * When RMODINPROGRESS is set it indicates that a uiomove() is in
     4215 +         * progress and the r_size has not been made consistent with the
     4216 +         * new size of the file. When the uiomove() completes the r_size is
     4217 +         * updated and the RMODINPROGRESS flag is cleared.
     4218 +         *
     4219 +         * The RMODINPROGRESS flag makes sure that smbfs_bio() sees a
     4220 +         * consistent value of r_size. Without this handshaking, it is
     4221 +         * possible that smbfs_bio() picks  up the old value of r_size
     4222 +         * before the uiomove() in writerp() completes. This will result
     4223 +         * in the write through smbfs_bio() being dropped.
     4224 +         *
     4225 +         * More precisely, there is a window between the time the uiomove()
     4226 +         * completes and the time the r_size is updated. If a VOP_PUTPAGE()
     4227 +         * operation intervenes in this window, the page will be picked up,
     4228 +         * because it is dirty (it will be unlocked, unless it was
     4229 +         * pagecreate'd). When the page is picked up as dirty, the dirty
     4230 +         * bit is reset (pvn_getdirty()). In smbfs_write(), r_size is
     4231 +         * checked. This will still be the old size. Therefore the page will
     4232 +         * not be written out. When segmap_release() calls VOP_PUTPAGE(),
     4233 +         * the page will be found to be clean and the write will be dropped.
     4234 +         */
     4235 +        if (np->r_flags & RMODINPROGRESS) {
     4236 +                mutex_enter(&np->r_statelock);
     4237 +                if ((np->r_flags & RMODINPROGRESS) &&
     4238 +                    np->r_modaddr + MAXBSIZE > io_off &&
     4239 +                    np->r_modaddr < io_off + io_len) {
     4240 +                        page_t *plist;
     4241 +                        /*
     4242 +                         * A write is in progress for this region of the file.
     4243 +                         * If we did not detect RMODINPROGRESS here then this
     4244 +                         * path through smbfs_putapage() would eventually go to
     4245 +                         * smbfs_bio() and may not write out all of the data
     4246 +                         * in the pages. We end up losing data. So we decide
     4247 +                         * to set the modified bit on each page in the page
     4248 +                         * list and mark the rnode with RDIRTY. This write
     4249 +                         * will be restarted at some later time.
     4250 +                         */
     4251 +                        plist = pp;
     4252 +                        while (plist != NULL) {
     4253 +                                pp = plist;
     4254 +                                page_sub(&plist, pp);
     4255 +                                hat_setmod(pp);
     4256 +                                page_io_unlock(pp);
     4257 +                                page_unlock(pp);
     4258 +                        }
     4259 +                        np->r_flags |= RDIRTY;
     4260 +                        mutex_exit(&np->r_statelock);
     4261 +                        if (offp)
     4262 +                                *offp = io_off;
     4263 +                        if (lenp)
     4264 +                                *lenp = io_len;
     4265 +                        return (0);
     4266 +                }
     4267 +                mutex_exit(&np->r_statelock);
     4268 +        }
     4269 +
     4270 +        /*
     4271 +         * NFS handles (flags & B_ASYNC) here...
     4272 +         * (See nfs_async_putapage())
     4273 +         *
     4274 +         * This code section from: nfs3_sync_putapage()
     4275 +         */
     4276 +
     4277 +        flags |= B_WRITE;
     4278 +
     4279 +        error = smbfs_rdwrlbn(vp, pp, io_off, io_len, flags, cr);
     4280 +
     4281 +        if ((error == ENOSPC || error == EDQUOT || error == EFBIG ||
     4282 +            error == EACCES) &&
     4283 +            (flags & (B_INVAL|B_FORCE)) != (B_INVAL|B_FORCE)) {
     4284 +                if (!(np->r_flags & ROUTOFSPACE)) {
     4285 +                        mutex_enter(&np->r_statelock);
     4286 +                        np->r_flags |= ROUTOFSPACE;
     4287 +                        mutex_exit(&np->r_statelock);
     4288 +                }
     4289 +                flags |= B_ERROR;
     4290 +                pvn_write_done(pp, flags);
     4291 +                /*
     4292 +                 * If this was not an async thread, then try again to
     4293 +                 * write out the pages, but this time, also destroy
     4294 +                 * them whether or not the write is successful.  This
     4295 +                 * will prevent memory from filling up with these
     4296 +                 * pages and destroying them is the only alternative
     4297 +                 * if they can't be written out.
     4298 +                 *
     4299 +                 * Don't do this if this is an async thread because
     4300 +                 * when the pages are unlocked in pvn_write_done,
     4301 +                 * some other thread could have come along, locked
     4302 +                 * them, and queued for an async thread.  It would be
     4303 +                 * possible for all of the async threads to be tied
     4304 +                 * up waiting to lock the pages again and they would
     4305 +                 * all already be locked and waiting for an async
     4306 +                 * thread to handle them.  Deadlock.
     4307 +                 */
     4308 +                if (!(flags & B_ASYNC)) {
     4309 +                        error = smbfs_putpage(vp, io_off, io_len,
     4310 +                            B_INVAL | B_FORCE, cr, NULL);
     4311 +                }
     4312 +        } else {
     4313 +                if (error)
     4314 +                        flags |= B_ERROR;
     4315 +                else if (np->r_flags & ROUTOFSPACE) {
     4316 +                        mutex_enter(&np->r_statelock);
     4317 +                        np->r_flags &= ~ROUTOFSPACE;
     4318 +                        mutex_exit(&np->r_statelock);
     4319 +                }
     4320 +                pvn_write_done(pp, flags);
     4321 +        }
     4322 +
     4323 +        /* Now more code from: nfs3_putapage */
     4324 +
     4325 +        if (offp)
     4326 +                *offp = io_off;
     4327 +        if (lenp)
     4328 +                *lenp = io_len;
     4329 +
     4330 +        return (error);
     4331 +}
     4332 +
     4333 +/*
     4334 + * NFS has this in nfs_client.c (shared by v2,v3,...)
     4335 + * We have it here so smbfs_putapage can be file scope.
     4336 + */
     4337 +void
     4338 +smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
     4339 +{
     4340 +        smbnode_t *np;
     4341 +
     4342 +        np = VTOSMB(vp);
     4343 +
     4344 +        mutex_enter(&np->r_statelock);
     4345 +        while (np->r_flags & RTRUNCATE)
     4346 +                cv_wait(&np->r_cv, &np->r_statelock);
     4347 +        np->r_flags |= RTRUNCATE;
     4348 +
     4349 +        if (off == (u_offset_t)0) {
     4350 +                np->r_flags &= ~RDIRTY;
     4351 +                if (!(np->r_flags & RSTALE))
     4352 +                        np->r_error = 0;
     4353 +        }
     4354 +        /* Here NFSv3 has np->r_truncaddr = off; */
     4355 +        mutex_exit(&np->r_statelock);
     4356 +
     4357 +        (void) pvn_vplist_dirty(vp, off, smbfs_putapage,
     4358 +            B_INVAL | B_TRUNC, cr);
     4359 +
     4360 +        mutex_enter(&np->r_statelock);
     4361 +        np->r_flags &= ~RTRUNCATE;
     4362 +        cv_broadcast(&np->r_cv);
     4363 +        mutex_exit(&np->r_statelock);
     4364 +}
     4365 +
     4366 +/* Like nfs3_map */
     4367 +
     4368 +/* ARGSUSED */
     4369 +static int
     4370 +smbfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
     4371 +        size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
     4372 +        cred_t *cr, caller_context_t *ct)
     4373 +{
     4374 +        segvn_crargs_t  vn_a;
     4375 +        struct vattr    va;
     4376 +        smbnode_t       *np;
     4377 +        smbmntinfo_t    *smi;
     4378 +        int             error;
     4379 +
     4380 +        np = VTOSMB(vp);
     4381 +        smi = VTOSMI(vp);
     4382 +
     4383 +        if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
     4384 +                return (EIO);
     4385 +
     4386 +        if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
     4387 +                return (EIO);
     4388 +
     4389 +        if (vp->v_flag & VNOMAP)
     4390 +                return (ENOSYS);
     4391 +
     4392 +        if (off < 0 || off + (ssize_t)len < 0)
     4393 +                return (ENXIO);
     4394 +
     4395 +        if (vp->v_type != VREG)
     4396 +                return (ENODEV);
     4397 +
     4398 +        /*
     4399 +         * NFS does close-to-open consistency stuff here.
     4400 +         * Just get (possibly cached) attributes.
     4401 +         */
     4402 +        va.va_mask = AT_ALL;
     4403 +        if ((error = smbfsgetattr(vp, &va, cr)) != 0)
     4404 +                return (error);
     4405 +
     4406 +        /*
     4407 +         * Check to see if the vnode is currently marked as not cachable.
     4408 +         * This means portions of the file are locked (through VOP_FRLOCK).
     4409 +         * In this case the map request must be refused.  We use
     4410 +         * rp->r_lkserlock to avoid a race with concurrent lock requests.
     4411 +         */
     4412 +        /*
     4413 +         * Atomically increment r_inmap after acquiring r_rwlock. The
     4414 +         * idea here is to acquire r_rwlock to block read/write and
     4415 +         * not to protect r_inmap. r_inmap will inform smbfs_read/write()
     4416 +         * that we are in smbfs_map(). Now, r_rwlock is acquired in order
     4417 +         * and we can prevent the deadlock that would have occurred
     4418 +         * when smbfs_addmap() would have acquired it out of order.
     4419 +         *
     4420 +         * Since we are not protecting r_inmap by any lock, we do not
     4421 +         * hold any lock when we decrement it. We atomically decrement
     4422 +         * r_inmap after we release r_lkserlock.  Note that rwlock is
     4423 +         * re-entered as writer in smbfs_addmap (called via as_map).
     4424 +         */
     4425 +
     4426 +        if (smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, SMBINTR(vp)))
     4427 +                return (EINTR);
     4428 +        atomic_inc_uint(&np->r_inmap);
     4429 +        smbfs_rw_exit(&np->r_rwlock);
     4430 +
     4431 +        if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) {
     4432 +                atomic_dec_uint(&np->r_inmap);
     4433 +                return (EINTR);
     4434 +        }
     4435 +
     4436 +        if (vp->v_flag & VNOCACHE) {
     4437 +                error = EAGAIN;
     4438 +                goto done;
     4439 +        }
     4440 +
     4441 +        /*
     4442 +         * Don't allow concurrent locks and mapping if mandatory locking is
     4443 +         * enabled.
     4444 +         */
     4445 +        if ((flk_has_remote_locks(vp) || smbfs_lm_has_sleep(vp)) &&
     4446 +            MANDLOCK(vp, va.va_mode)) {
     4447 +                error = EAGAIN;
     4448 +                goto done;
     4449 +        }
     4450 +
     4451 +        as_rangelock(as);
     4452 +        error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
     4453 +        if (error != 0) {
     4454 +                as_rangeunlock(as);
     4455 +                goto done;
     4456 +        }
     4457 +
     4458 +        vn_a.vp = vp;
     4459 +        vn_a.offset = off;
     4460 +        vn_a.type = (flags & MAP_TYPE);
     4461 +        vn_a.prot = (uchar_t)prot;
     4462 +        vn_a.maxprot = (uchar_t)maxprot;
     4463 +        vn_a.flags = (flags & ~MAP_TYPE);
     4464 +        vn_a.cred = cr;
     4465 +        vn_a.amp = NULL;
     4466 +        vn_a.szc = 0;
     4467 +        vn_a.lgrp_mem_policy_flags = 0;
     4468 +
     4469 +        error = as_map(as, *addrp, len, segvn_create, &vn_a);
     4470 +        as_rangeunlock(as);
     4471 +
     4472 +done:
     4473 +        smbfs_rw_exit(&np->r_lkserlock);
     4474 +        atomic_dec_uint(&np->r_inmap);
     4475 +        return (error);
     4476 +}
     4477 +
     4478 +/* ARGSUSED */
     4479 +static int
     4480 +smbfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
     4481 +        size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
     4482 +        cred_t *cr, caller_context_t *ct)
     4483 +{
     4484 +        smbnode_t *np = VTOSMB(vp);
     4485 +        boolean_t inc_fidrefs = B_FALSE;
     4486 +
     4487 +        /*
     4488 +         * When r_mapcnt goes from zero to non-zero,
     4489 +         * increment n_fidrefs
     4490 +         */
     4491 +        mutex_enter(&np->r_statelock);
     4492 +        if (np->r_mapcnt == 0)
     4493 +                inc_fidrefs = B_TRUE;
     4494 +        np->r_mapcnt += btopr(len);
     4495 +        mutex_exit(&np->r_statelock);
     4496 +
     4497 +        if (inc_fidrefs) {
     4498 +                (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
     4499 +                np->n_fidrefs++;
     4500 +                smbfs_rw_exit(&np->r_lkserlock);
     4501 +        }
     4502 +
     4503 +        return (0);
     4504 +}
     4505 +
     4506 +/*
     4507 + * Use an address space callback to flush pages dirty pages after unmap,
     4508 + * which we can't do directly in smbfs_delmap due to locking issues.
     4509 + */
     4510 +typedef struct smbfs_delmap_args {
     4511 +        vnode_t                 *vp;
     4512 +        cred_t                  *cr;
     4513 +        offset_t                off;
     4514 +        caddr_t                 addr;
     4515 +        size_t                  len;
     4516 +        uint_t                  prot;
     4517 +        uint_t                  maxprot;
     4518 +        uint_t                  flags;
     4519 +        boolean_t               dec_fidrefs;
     4520 +} smbfs_delmap_args_t;
     4521 +
     4522 +/* ARGSUSED */
     4523 +static int
     4524 +smbfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
     4525 +        size_t len, uint_t prot, uint_t maxprot, uint_t flags,
     4526 +        cred_t *cr, caller_context_t *ct)
     4527 +{
     4528 +        smbnode_t *np = VTOSMB(vp);
     4529 +        smbfs_delmap_args_t     *dmapp;
     4530 +        int error;
     4531 +
     4532 +        dmapp = kmem_zalloc(sizeof (*dmapp), KM_SLEEP);
     4533 +
     4534 +        dmapp->vp = vp;
     4535 +        dmapp->off = off;
     4536 +        dmapp->addr = addr;
     4537 +        dmapp->len = len;
     4538 +        dmapp->prot = prot;
     4539 +        dmapp->maxprot = maxprot;
     4540 +        dmapp->flags = flags;
     4541 +        dmapp->cr = cr;
     4542 +        dmapp->dec_fidrefs = B_FALSE;
     4543 +
     4544 +        /*
     4545 +         * When r_mapcnt returns to zero, arrange for the
     4546 +         * callback to decrement n_fidrefs
     4547 +         */
     4548 +        mutex_enter(&np->r_statelock);
     4549 +        np->r_mapcnt -= btopr(len);
     4550 +        ASSERT(np->r_mapcnt >= 0);
     4551 +        if (np->r_mapcnt == 0)
     4552 +                dmapp->dec_fidrefs = B_TRUE;
     4553 +        mutex_exit(&np->r_statelock);
     4554 +
     4555 +        error = as_add_callback(as, smbfs_delmap_callback, dmapp,
     4556 +            AS_UNMAP_EVENT, addr, len, KM_SLEEP);
     4557 +        if (error != 0) {
     4558 +                /*
     4559 +                 * So sad, no callback is coming. Can't flush pages
     4560 +                 * in delmap (as locks).  Just handle n_fidrefs.
     4561 +                 */
     4562 +                cmn_err(CE_NOTE, "smbfs_delmap(%p) "
     4563 +                    "as_add_callback err=%d",
     4564 +                    (void *)vp, error);
     4565 +
     4566 +                if (dmapp->dec_fidrefs) {
     4567 +                        struct smb_cred scred;
     4568 +
     4569 +                        (void) smbfs_rw_enter_sig(&np->r_lkserlock,
     4570 +                            RW_WRITER, 0);
     4571 +                        smb_credinit(&scred, dmapp->cr);
     4572 +
     4573 +                        smbfs_rele_fid(np, &scred);
     4574 +
     4575 +                        smb_credrele(&scred);
     4576 +                        smbfs_rw_exit(&np->r_lkserlock);
     4577 +                }
     4578 +                kmem_free(dmapp, sizeof (*dmapp));
     4579 +        }
     4580 +
     4581 +        return (0);
     4582 +}
     4583 +
     4584 +/*
     4585 + * Remove some pages from an mmap'd vnode.  Flush any
     4586 + * dirty pages in the unmapped range.
     4587 + */
     4588 +/* ARGSUSED */
     4589 +static void
     4590 +smbfs_delmap_callback(struct as *as, void *arg, uint_t event)
     4591 +{
     4592 +        vnode_t                 *vp;
     4593 +        smbnode_t               *np;
     4594 +        smbmntinfo_t            *smi;
     4595 +        smbfs_delmap_args_t     *dmapp = arg;
     4596 +
     4597 +        vp = dmapp->vp;
     4598 +        np = VTOSMB(vp);
     4599 +        smi = VTOSMI(vp);
     4600 +
     4601 +        /* Decremented r_mapcnt in smbfs_delmap */
     4602 +
     4603 +        /*
     4604 +         * Initiate a page flush and potential commit if there are
     4605 +         * pages, the file system was not mounted readonly, the segment
     4606 +         * was mapped shared, and the pages themselves were writeable.
     4607 +         *
     4608 +         * mark RDIRTY here, will be used to check if a file is dirty when
     4609 +         * unmount smbfs
     4610 +         */
     4611 +        if (vn_has_cached_data(vp) && !vn_is_readonly(vp) &&
     4612 +            dmapp->flags == MAP_SHARED && (dmapp->maxprot & PROT_WRITE)) {
     4613 +                mutex_enter(&np->r_statelock);
     4614 +                np->r_flags |= RDIRTY;
     4615 +                mutex_exit(&np->r_statelock);
     4616 +
     4617 +                /*
     4618 +                 * Need to finish the putpage before we
     4619 +                 * close the OtW FID needed for I/O.
     4620 +                 */
     4621 +                (void) smbfs_putpage(vp, dmapp->off, dmapp->len, 0,
     4622 +                    dmapp->cr, NULL);
     4623 +        }
     4624 +
     4625 +        if ((np->r_flags & RDIRECTIO) || (smi->smi_flags & SMI_DIRECTIO))
     4626 +                (void) smbfs_putpage(vp, dmapp->off, dmapp->len,
     4627 +                    B_INVAL, dmapp->cr, NULL);
     4628 +
     4629 +        /*
     4630 +         * If r_mapcnt went to zero, drop our FID ref now.
     4631 +         * On the last fidref, this does an OtW close.
     4632 +         */
     4633 +        if (dmapp->dec_fidrefs) {
     4634 +                struct smb_cred scred;
     4635 +
     4636 +                (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
     4637 +                smb_credinit(&scred, dmapp->cr);
     4638 +
     4639 +                smbfs_rele_fid(np, &scred);
     4640 +
     4641 +                smb_credrele(&scred);
     4642 +                smbfs_rw_exit(&np->r_lkserlock);
     4643 +        }
     4644 +
     4645 +        (void) as_delete_callback(as, arg);
     4646 +        kmem_free(dmapp, sizeof (*dmapp));
     4647 +}
     4648 +
     4649 +/* No smbfs_pageio() or smbfs_dispose() ops. */
     4650 +
     4651 +/* misc. ******************************************************** */
     4652 +
     4653 +
     4654 +/*
2971 4655   * XXX
2972 4656   * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2973 4657   */
2974 4658  static int
2975 4659  smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2976 4660          offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2977 4661          caller_context_t *ct)
2978 4662  {
2979 4663          if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2980 4664                  return (EIO);
↓ open down ↓ 49 lines elided ↑ open up ↑
3030 4714                           * mtime if we truncate the file to its
3031 4715                           * previous size.
3032 4716                           */
3033 4717                          va.va_mask = AT_SIZE;
3034 4718                          error = smbfsgetattr(vp, &va, cr);
3035 4719                          if (error || va.va_size == bfp->l_start)
3036 4720                                  return (error);
3037 4721                          va.va_mask = AT_SIZE;
3038 4722                          va.va_size = bfp->l_start;
3039 4723                          error = smbfssetattr(vp, &va, 0, cr);
     4724 +                        /* SMBFS_VNEVENT... */
3040 4725                  } else
3041 4726                          error = EINVAL;
3042 4727          }
3043 4728  
3044 4729          return (error);
3045 4730  }
3046 4731  
     4732 +
3047 4733  /* ARGSUSED */
3048 4734  static int
     4735 +smbfs_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
     4736 +{
     4737 +
     4738 +        return (ENOSYS);
     4739 +}
     4740 +
     4741 +
     4742 +/* ARGSUSED */
     4743 +static int
3049 4744  smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
3050 4745          caller_context_t *ct)
3051 4746  {
3052 4747          vfs_t *vfs;
3053 4748          smbmntinfo_t *smi;
3054 4749          struct smb_share *ssp;
3055 4750  
3056 4751          vfs = vp->v_vfsp;
3057 4752          smi = VFTOSMI(vfs);
3058 4753  
↓ open down ↓ 154 lines elided ↑ open up ↑
3213 4908          caller_context_t *ct)
3214 4909  {
3215 4910          if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3216 4911                  return (EIO);
3217 4912  
3218 4913          if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3219 4914                  return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3220 4915          else
3221 4916                  return (ENOSYS);
3222 4917  }
     4918 +
     4919 +
     4920 +/*
     4921 + * Most unimplemented ops will return ENOSYS because of fs_nosys().
     4922 + * The only ops where that won't work are ACCESS (due to open(2)
     4923 + * failures) and ... (anything else left?)
     4924 + */
     4925 +const fs_operation_def_t smbfs_vnodeops_template[] = {
     4926 +        VOPNAME_OPEN,           { .vop_open = smbfs_open },
     4927 +        VOPNAME_CLOSE,          { .vop_close = smbfs_close },
     4928 +        VOPNAME_READ,           { .vop_read = smbfs_read },
     4929 +        VOPNAME_WRITE,          { .vop_write = smbfs_write },
     4930 +        VOPNAME_IOCTL,          { .vop_ioctl = smbfs_ioctl },
     4931 +        VOPNAME_GETATTR,        { .vop_getattr = smbfs_getattr },
     4932 +        VOPNAME_SETATTR,        { .vop_setattr = smbfs_setattr },
     4933 +        VOPNAME_ACCESS,         { .vop_access = smbfs_access },
     4934 +        VOPNAME_LOOKUP,         { .vop_lookup = smbfs_lookup },
     4935 +        VOPNAME_CREATE,         { .vop_create = smbfs_create },
     4936 +        VOPNAME_REMOVE,         { .vop_remove = smbfs_remove },
     4937 +        VOPNAME_LINK,           { .vop_link = smbfs_link },
     4938 +        VOPNAME_RENAME,         { .vop_rename = smbfs_rename },
     4939 +        VOPNAME_MKDIR,          { .vop_mkdir = smbfs_mkdir },
     4940 +        VOPNAME_RMDIR,          { .vop_rmdir = smbfs_rmdir },
     4941 +        VOPNAME_READDIR,        { .vop_readdir = smbfs_readdir },
     4942 +        VOPNAME_SYMLINK,        { .vop_symlink = smbfs_symlink },
     4943 +        VOPNAME_READLINK,       { .vop_readlink = smbfs_readlink },
     4944 +        VOPNAME_FSYNC,          { .vop_fsync = smbfs_fsync },
     4945 +        VOPNAME_INACTIVE,       { .vop_inactive = smbfs_inactive },
     4946 +        VOPNAME_FID,            { .vop_fid = smbfs_fid },
     4947 +        VOPNAME_RWLOCK,         { .vop_rwlock = smbfs_rwlock },
     4948 +        VOPNAME_RWUNLOCK,       { .vop_rwunlock = smbfs_rwunlock },
     4949 +        VOPNAME_SEEK,           { .vop_seek = smbfs_seek },
     4950 +        VOPNAME_FRLOCK,         { .vop_frlock = smbfs_frlock },
     4951 +        VOPNAME_SPACE,          { .vop_space = smbfs_space },
     4952 +        VOPNAME_REALVP,         { .vop_realvp = smbfs_realvp },
     4953 +        VOPNAME_GETPAGE,        { .vop_getpage = smbfs_getpage },
     4954 +        VOPNAME_PUTPAGE,        { .vop_putpage = smbfs_putpage },
     4955 +        VOPNAME_MAP,            { .vop_map = smbfs_map },
     4956 +        VOPNAME_ADDMAP,         { .vop_addmap = smbfs_addmap },
     4957 +        VOPNAME_DELMAP,         { .vop_delmap = smbfs_delmap },
     4958 +        VOPNAME_DUMP,           { .error = fs_nosys }, /* smbfs_dump, */
     4959 +        VOPNAME_PATHCONF,       { .vop_pathconf = smbfs_pathconf },
     4960 +        VOPNAME_PAGEIO,         { .error = fs_nosys }, /* smbfs_pageio, */
     4961 +        VOPNAME_SETSECATTR,     { .vop_setsecattr = smbfs_setsecattr },
     4962 +        VOPNAME_GETSECATTR,     { .vop_getsecattr = smbfs_getsecattr },
     4963 +        VOPNAME_SHRLOCK,        { .vop_shrlock = smbfs_shrlock },
     4964 +#ifdef  SMBFS_VNEVENT
     4965 +        VOPNAME_VNEVENT,        { .vop_vnevent = fs_vnevent_support },
     4966 +#endif
     4967 +        { NULL, NULL }
     4968 +};
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX