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
   1    1  /*
   2    2   * Copyright (c) 2000-2001 Boris Popov
   3    3   * All rights reserved.
   4    4   *
   5    5   * Redistribution and use in source and binary forms, with or without
   6    6   * modification, are permitted provided that the following conditions
   7    7   * are met:
   8    8   * 1. Redistributions of source code must retain the above copyright
   9    9   *    notice, this list of conditions and the following disclaimer.
  10   10   * 2. Redistributions in binary form must reproduce the above copyright
  11   11   *    notice, this list of conditions and the following disclaimer in the
  12   12   *    documentation and/or other materials provided with the distribution.
  13   13   * 3. All advertising materials mentioning features or use of this software
  14   14   *    must display the following acknowledgement:
  15   15   *    This product includes software developed by Boris Popov.
  16   16   * 4. Neither the name of the author nor the names of any co-contributors
  17   17   *    may be used to endorse or promote products derived from this software
  18   18   *    without specific prior written permission.
  19   19   *
  20   20   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21   21   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22   22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23   23   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24   24   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25   25   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26   26   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27   27   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28   28   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  
    | 
      ↓ 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>
  64   83  #include <fs/fs_subr.h>
  65   84  
  66   85  /*
  67   86   * We assign directory offsets like the NFS client, where the
  68   87   * offset increments by _one_ after each directory entry.
  69   88   * Further, the entries "." and ".." are always at offsets
  70   89   * zero and one (respectively) and the "real" entries from
  71   90   * the server appear at offsets starting with two.  This
  72   91   * macro is used to initialize the n_dirofs field after
  73   92   * setting n_dirseq with a _findopen call.
  74   93   */
  75   94  #define FIRST_DIROFS    2
  76   95  
  77   96  /*
  78   97   * These characters are illegal in NTFS file names.
  79   98   * ref: http://support.microsoft.com/kb/147438
  80   99   *
  81  100   * Careful!  The check in the XATTR case skips the
  82  101   * first character to allow colon in XATTR names.
  83  102   */
  84  103  static const char illegal_chars[] = {
  85  104          ':',    /* colon - keep this first! */
  86  105          '\\',   /* back slash */
  87  106          '/',    /* slash */
  88  107          '*',    /* asterisk */
  89  108          '?',    /* question mark */
  90  109          '"',    /* double quote */
  91  110          '<',    /* less than sign */
  92  111          '>',    /* greater than sign */
  93  112          '|',    /* vertical bar */
  
    | 
      ↓ 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;
 246  191          vnode_t         *vp;
 247  192          smbfattr_t      fa;
 248  193          u_int32_t       rights, rightsrcvd;
 249  194          u_int16_t       fid, oldfid;
 250  195          int             oldgenid;
 251  196          struct smb_cred scred;
 252  197          smbmntinfo_t    *smi;
 253  198          smb_share_t     *ssp;
 254  199          cred_t          *oldcr;
 255  200          int             tmperror;
 256  201          int             error = 0;
 257  202  
 258  203          vp = *vpp;
 259  204          np = VTOSMB(vp);
 260  205          smi = VTOSMI(vp);
 261  206          ssp = smi->smi_share;
 262  207  
 263  208          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 264  209                  return (EIO);
 265  210  
 266  211          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 267  212                  return (EIO);
 268  213  
 269  214          if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
 270  215                  SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
 271  216                  return (EACCES);
 272  217          }
 273  218  
 274  219          /*
 275  220           * Get exclusive access to n_fid and related stuff.
 276  221           * No returns after this until out.
  
    | 
      ↓ 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          }
 298  242  
 299  243          /*
 300  244           * Directory open.  See smbfs_readvdir()
 301  245           */
 302  246          if (vp->v_type == VDIR) {
 303  247                  if (np->n_dirseq == NULL) {
 304  248                          /* first open */
 305  249                          error = smbfs_smb_findopen(np, "*", 1,
 306  250                              SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
 307  251                              &scred, &np->n_dirseq);
 308  252                          if (error != 0)
 309  253                                  goto out;
 310  254                  }
 311  255                  np->n_dirofs = FIRST_DIROFS;
 312  256                  np->n_dirrefs++;
 313  257                  goto have_fid;
 314  258          }
 315  259  
 316  260          /*
 317  261           * If caller specified O_TRUNC/FTRUNC, then be sure to set
 318  262           * FWRITE (to drive successful setattr(size=0) after open)
 319  263           */
 320  264          if (flag & FTRUNC)
 321  265                  flag |= FWRITE;
 322  266  
 323  267          /*
 324  268           * If we already have it open, and the FID is still valid,
 325  269           * check whether the rights are sufficient for FID reuse.
 326  270           */
 327  271          if (np->n_fidrefs > 0 &&
 328  272              np->n_vcgenid == ssp->ss_vcgenid) {
 329  273                  int upgrade = 0;
 330  274  
 331  275                  if ((flag & FWRITE) &&
 332  276                      !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
 333  277                          upgrade = 1;
 334  278                  if ((flag & FREAD) &&
 335  279                      !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
 336  280                          upgrade = 1;
 337  281                  if (!upgrade) {
 338  282                          /*
 339  283                           *  the existing open is good enough
 340  284                           */
 341  285                          np->n_fidrefs++;
 342  286                          goto have_fid;
 343  287                  }
 344  288          }
 345  289          rights = np->n_fidrefs ? np->n_rights : 0;
 346  290  
 347  291          /*
 348  292           * we always ask for READ_CONTROL so we can always get the
 349  293           * owner/group IDs to satisfy a stat.  Ditto attributes.
 350  294           */
 351  295          rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
 352  296              SA_RIGHT_FILE_READ_ATTRIBUTES);
 353  297          if ((flag & FREAD))
 354  298                  rights |= SA_RIGHT_FILE_READ_DATA;
 355  299          if ((flag & FWRITE))
 356  300                  rights |= SA_RIGHT_FILE_WRITE_DATA |
 357  301                      SA_RIGHT_FILE_APPEND_DATA |
 358  302                      SA_RIGHT_FILE_WRITE_ATTRIBUTES;
 359  303  
 360  304          bzero(&fa, sizeof (fa));
 361  305          error = smbfs_smb_open(np,
 362  306              NULL, 0, 0, /* name nmlen xattr */
 363  307              rights, &scred,
 364  308              &fid, &rightsrcvd, &fa);
 365  309          if (error)
 366  310                  goto out;
 367  311          smbfs_attrcache_fa(vp, &fa);
 368  312  
 369  313          /*
 370  314           * We have a new FID and access rights.
 371  315           */
 372  316          oldfid = np->n_fid;
 373  317          oldgenid = np->n_vcgenid;
 374  318          np->n_fid = fid;
 375  319          np->n_vcgenid = ssp->ss_vcgenid;
 376  320          np->n_rights = rightsrcvd;
 377  321          np->n_fidrefs++;
 378  322          if (np->n_fidrefs > 1 &&
 379  323              oldgenid == ssp->ss_vcgenid) {
 380  324                  /*
 381  325                   * We already had it open (presumably because
 382  326                   * it was open with insufficient rights.)
 383  327                   * Close old wire-open.
 384  328                   */
 385  329                  tmperror = smbfs_smb_close(ssp,
 386  330                      oldfid, NULL, &scred);
 387  331                  if (tmperror)
 388  332                          SMBVDEBUG("error %d closing %s\n",
 389  333                              tmperror, np->n_rpath);
 390  334          }
 391  335  
 392  336          /*
 393  337           * This thread did the open.
 394  338           * Save our credentials too.
 395  339           */
 396  340          mutex_enter(&np->r_statelock);
 397  341          oldcr = np->r_cred;
 398  342          np->r_cred = cr;
 399  343          crhold(cr);
 400  344          if (oldcr)
 401  345                  crfree(oldcr);
 402  346          mutex_exit(&np->r_statelock);
 403  347  
 404  348  have_fid:
 405  349          /*
 406  350           * Keep track of the vnode type at first open.
 407  351           * (see comments above)
 408  352           */
 409  353          if (np->n_ovtype == VNON)
 410  354                  np->n_ovtype = vp->v_type;
 411  355  
 412  356  out:
 413  357          smb_credrele(&scred);
 414  358          smbfs_rw_exit(&np->r_lkserlock);
 415  359          return (error);
  
    | 
      ↓ 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          /*
 436  381           * zone_enter(2) prevents processes from changing zones with SMBFS files
 437  382           * open; if we happen to get here from the wrong zone we can't do
 438  383           * anything over the wire.
 439  384           */
 440  385          if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
 441  386                  /*
 442  387                   * We could attempt to clean up locks, except we're sure
 443  388                   * that the current process didn't acquire any locks on
 444  389                   * the file: any attempt to lock a file belong to another zone
 445  390                   * will fail, and one can't lock an SMBFS file and then change
 446  391                   * zones, as that fails too.
 447  392                   *
 448  393                   * Returning an error here is the sane thing to do.  A
 449  394                   * subsequent call to VN_RELE() which translates to a
 450  395                   * smbfs_inactive() will clean up state: if the zone of the
 451  396                   * vnode's origin is still alive and kicking, an async worker
 452  397                   * thread will handle the request (from the correct zone), and
 453  398                   * everything (minus the final smbfs_getattr_otw() call) should
 454  399                   * be OK. If the zone is going away smbfs_async_inactive() will
 455  400                   * throw away cached pages inline.
 456  401                   */
 457  402                  return (EIO);
 458  403          }
 459  404  
 460  405          /*
 461  406           * If we are using local locking for this filesystem, then
 462  407           * release all of the SYSV style record locks.  Otherwise,
  
    | 
      ↓ 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);
 493  464  
 494  465          smb_credrele(&scred);
 495  466          smbfs_rw_exit(&np->r_lkserlock);
 496  467  
 497  468          return (0);
 498  469  }
 499  470  
 500  471  /*
 501  472   * Helper for smbfs_close.  Decrement the reference count
 502  473   * for an SMB-level file or directory ID, and when the last
 503  474   * reference for the fid goes away, do the OtW close.
 504  475   * Also called in smbfs_inactive (defensive cleanup).
 505  476   */
 506  477  static void
 507  478  smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
 508  479  {
 509  480          smb_share_t     *ssp;
 510  481          cred_t          *oldcr;
 511  482          struct smbfs_fctx *fctx;
 512  483          int             error;
 513  484          uint16_t ofid;
 514  485  
 515  486          ssp = np->n_mount->smi_share;
 516  487          error = 0;
 517  488  
 518  489          /* Make sure we serialize for n_dirseq use. */
 519  490          ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
 520  491  
 521  492          /*
 522  493           * Note that vp->v_type may change if a remote node
 523  494           * is deleted and recreated as a different type, and
 524  495           * our getattr may change v_type accordingly.
 525  496           * Now use n_ovtype to keep track of the v_type
 526  497           * we had during open (see comments above).
 527  498           */
 528  499          switch (np->n_ovtype) {
 529  500          case VDIR:
 530  501                  ASSERT(np->n_dirrefs > 0);
 531  502                  if (--np->n_dirrefs)
 532  503                          return;
 533  504                  if ((fctx = np->n_dirseq) != NULL) {
 534  505                          np->n_dirseq = NULL;
 535  506                          np->n_dirofs = 0;
 536  507                          error = smbfs_smb_findclose(fctx, scred);
 537  508                  }
 538  509                  break;
 539  510  
 540  511          case VREG:
 541  512                  ASSERT(np->n_fidrefs > 0);
 542  513                  if (--np->n_fidrefs)
 543  514                          return;
 544  515                  if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
 545  516                          np->n_fid = SMB_FID_UNUSED;
 546  517                          /* After reconnect, n_fid is invalid */
 547  518                          if (np->n_vcgenid == ssp->ss_vcgenid) {
 548  519                                  error = smbfs_smb_close(
 549  520                                      ssp, ofid, NULL, scred);
 550  521                          }
 551  522                  }
 552  523                  break;
 553  524  
 554  525          default:
 555  526                  SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
 556  527                  break;
 557  528          }
 558  529          if (error) {
 559  530                  SMBVDEBUG("error %d closing %s\n",
 560  531                      error, np->n_rpath);
 561  532          }
 562  533  
 563  534          /* Allow next open to use any v_type. */
 564  535          np->n_ovtype = VNON;
 565  536  
 566  537          /*
 567  538           * Other "last close" stuff.
 568  539           */
 569  540          mutex_enter(&np->r_statelock);
 570  541          if (np->n_flag & NATTRCHANGED)
 571  542                  smbfs_attrcache_rm_locked(np);
 572  543          oldcr = np->r_cred;
 573  544          np->r_cred = NULL;
 574  545          mutex_exit(&np->r_statelock);
 575  546          if (oldcr != NULL)
 576  547                  crfree(oldcr);
 577  548  }
 578  549  
 579  550  /* ARGSUSED */
 580  551  static int
 581  552  smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 582  553          caller_context_t *ct)
  
    | 
      ↓ 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  
 603  580          ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
 604  581  
 605  582          if (vp->v_type != VREG)
 606  583                  return (EISDIR);
 607  584  
 608  585          if (uiop->uio_resid == 0)
 609  586                  return (0);
 610  587  
 611  588          /*
 612  589           * Like NFS3, just check for 63-bit overflow.
 613  590           * Our SMB layer takes care to return EFBIG
 614  591           * when it has to fallback to a 32-bit call.
 615  592           */
 616  593          endoff = uiop->uio_loffset + uiop->uio_resid;
 617  594          if (uiop->uio_loffset < 0 || endoff < 0)
 618  595                  return (EINVAL);
 619  596  
 620  597          /* get vnode attributes from server */
 621  598          va.va_mask = AT_SIZE | AT_MTIME;
 622  599          if (error = smbfsgetattr(vp, &va, cr))
 623  600                  return (error);
 624  601  
 625  602          /* Update mtime with mtime from server here? */
 626  603  
 627  604          /* if offset is beyond EOF, read nothing */
 628  605          if (uiop->uio_loffset >= va.va_size)
 629  606                  return (0);
 630  607  
 631  608          /*
  
    | 
      ↓ 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);
 687  739  
 688  740          ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
 689  741  
 690  742          if (vp->v_type != VREG)
 691  743                  return (EISDIR);
  
    | 
      ↓ 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           */
 718  772          endoff = uiop->uio_loffset + uiop->uio_resid;
 719  773          if (uiop->uio_loffset < 0 || endoff < 0)
 720  774                  return (EINVAL);
  
    | 
      ↓ 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:
 829 1418                  error = smbfs_acl_iocset(vp, arg, flag, cr);
 830 1419                  break;
 831 1420  
 832 1421          default:
 833 1422                  error = ENOTTY;
 834 1423                  break;
 835 1424          }
 836 1425  
 837 1426          return (error);
 838 1427  }
 839 1428  
 840 1429  
 841 1430  /*
  
    | 
      ↓ 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          /*
 862 1452           * If it has been specified that the return value will
 863 1453           * just be used as a hint, and we are only being asked
 864 1454           * for size, fsid or rdevid, then return the client's
 865 1455           * notion of these values without checking to make sure
 866 1456           * that the attribute cache is up to date.
 867 1457           * The whole point is to avoid an over the wire GETATTR
 868 1458           * call.
 869 1459           */
 870 1460          np = VTOSMB(vp);
 871 1461          if (flags & ATTR_HINT) {
 872 1462                  if (vap->va_mask ==
 873 1463                      (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
 874 1464                          mutex_enter(&np->r_statelock);
 875 1465                          if (vap->va_mask | AT_SIZE)
  
    | 
      ↓ 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  {
 896 1510          vfs_t           *vfsp;
 897 1511          smbmntinfo_t    *smi;
 898 1512          int             error;
 899 1513          uint_t          mask;
 900 1514          struct vattr    oldva;
 901 1515  
 902 1516          vfsp = vp->v_vfsp;
 903 1517          smi = VFTOSMI(vfsp);
 904 1518  
 905 1519          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 906 1520                  return (EIO);
 907 1521  
 908 1522          if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
 909 1523                  return (EIO);
 910 1524  
 911 1525          mask = vap->va_mask;
 912 1526          if (mask & AT_NOSET)
 913 1527                  return (EINVAL);
 914 1528  
 915 1529          if (vfsp->vfs_flag & VFS_RDONLY)
 916 1530                  return (EROFS);
 917 1531  
 918 1532          /*
 919 1533           * This is a _local_ access check so that only the owner of
 920 1534           * this mount can set attributes.  With ACLs enabled, the
 921 1535           * file owner can be different from the mount owner, and we
 922 1536           * need to check the _mount_ owner here.  See _access_rwx
 923 1537           */
 924 1538          bzero(&oldva, sizeof (oldva));
 925 1539          oldva.va_mask = AT_TYPE | AT_MODE;
 926 1540          error = smbfsgetattr(vp, &oldva, cr);
 927 1541          if (error)
 928 1542                  return (error);
 929 1543          oldva.va_mask |= AT_UID | AT_GID;
 930 1544          oldva.va_uid = smi->smi_uid;
 931 1545          oldva.va_gid = smi->smi_gid;
 932 1546  
 933 1547          error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
 934 1548              smbfs_accessx, vp);
 935 1549          if (error)
 936 1550                  return (error);
 937 1551  
 938 1552          if (mask & (AT_UID | AT_GID)) {
 939 1553                  if (smi->smi_flags & SMI_ACL)
 940 1554                          error = smbfs_acl_setids(vp, vap, cr);
 941 1555                  else
 942 1556                          error = ENOSYS;
 943 1557                  if (error != 0) {
 944 1558                          SMBVDEBUG("error %d seting UID/GID on %s",
 945 1559                              error, VTOSMB(vp)->n_rpath);
  
    | 
      ↓ 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  {
 967 1588          int             error = 0;
 968 1589          smbnode_t       *np = VTOSMB(vp);
 969 1590          uint_t          mask = vap->va_mask;
 970 1591          struct timespec *mtime, *atime;
 971 1592          struct smb_cred scred;
 972 1593          int             cerror, modified = 0;
 973 1594          unsigned short  fid;
 974 1595          int have_fid = 0;
 975 1596          uint32_t rights = 0;
 976 1597          uint32_t dosattr = 0;
 977 1598  
 978 1599          ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
 979 1600  
 980 1601          /*
 981 1602           * There are no settable attributes on the XATTR dir,
 982 1603           * so just silently ignore these.  On XATTR files,
 983 1604           * you can set the size but nothing else.
  
    | 
      ↓ 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);
1004 1650          smb_credinit(&scred, cr);
1005 1651  
1006 1652          /*
1007 1653           * If the caller has provided extensible attributes,
1008 1654           * map those into DOS attributes supported by SMB.
1009 1655           * Note: zero means "no change".
1010 1656           */
1011 1657          if (mask & AT_XVATTR)
1012 1658                  dosattr = xvattr_to_dosattr(np, vap);
1013 1659  
1014 1660          /*
1015 1661           * Will we need an open handle for this setattr?
1016 1662           * If so, what rights will we need?
1017 1663           */
1018 1664          if (dosattr || (mask & (AT_ATIME | AT_MTIME))) {
1019 1665                  rights |=
1020 1666                      SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1021 1667          }
1022 1668          if (mask & AT_SIZE) {
1023 1669                  rights |=
1024 1670                      SA_RIGHT_FILE_WRITE_DATA |
1025 1671                      SA_RIGHT_FILE_APPEND_DATA;
1026 1672          }
1027 1673  
1028 1674          /*
1029 1675           * Only SIZE really requires a handle, but it's
1030 1676           * simpler and more reliable to set via a handle.
1031 1677           * Some servers like NT4 won't set times by path.
1032 1678           * Also, we're usually setting everything anyway.
1033 1679           */
1034 1680          if (rights != 0) {
1035 1681                  error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1036 1682                  if (error) {
1037 1683                          SMBVDEBUG("error %d opening %s\n",
1038 1684                              error, np->n_rpath);
1039 1685                          goto out;
1040 1686                  }
1041 1687                  have_fid = 1;
1042 1688          }
1043 1689  
1044 1690          /*
  
    | 
      ↓ 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
1135 1792  xvattr_to_dosattr(smbnode_t *np, struct vattr *vap)
1136 1793  {
1137 1794          xvattr_t *xvap = (xvattr_t *)vap;
1138 1795          xoptattr_t *xoap = NULL;
1139 1796          uint32_t attr = np->r_attr.fa_attr;
1140 1797          boolean_t anyset = B_FALSE;
1141 1798  
1142 1799          if ((xoap = xva_getxoptattr(xvap)) == NULL)
1143 1800                  return (0);
1144 1801  
1145 1802          if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
1146 1803                  if (xoap->xoa_archive)
1147 1804                          attr |= SMB_FA_ARCHIVE;
1148 1805                  else
1149 1806                          attr &= ~SMB_FA_ARCHIVE;
1150 1807                  XVA_SET_RTN(xvap, XAT_ARCHIVE);
1151 1808                  anyset = B_TRUE;
1152 1809          }
1153 1810          if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
1154 1811                  if (xoap->xoa_system)
1155 1812                          attr |= SMB_FA_SYSTEM;
1156 1813                  else
1157 1814                          attr &= ~SMB_FA_SYSTEM;
1158 1815                  XVA_SET_RTN(xvap, XAT_SYSTEM);
1159 1816                  anyset = B_TRUE;
1160 1817          }
1161 1818          if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
1162 1819                  if (xoap->xoa_readonly)
1163 1820                          attr |= SMB_FA_RDONLY;
1164 1821                  else
1165 1822                          attr &= ~SMB_FA_RDONLY;
1166 1823                  XVA_SET_RTN(xvap, XAT_READONLY);
1167 1824                  anyset = B_TRUE;
1168 1825          }
1169 1826          if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
1170 1827                  if (xoap->xoa_hidden)
1171 1828                          attr |= SMB_FA_HIDDEN;
1172 1829                  else
1173 1830                          attr &= ~SMB_FA_HIDDEN;
1174 1831                  XVA_SET_RTN(xvap, XAT_HIDDEN);
1175 1832                  anyset = B_TRUE;
1176 1833          }
1177 1834  
1178 1835          if (anyset == B_FALSE)
1179 1836                  return (0);     /* no change */
1180 1837          if (attr == 0)
1181 1838                  attr = SMB_EFA_NORMAL;
1182 1839  
1183 1840          return (attr);
1184 1841  }
1185 1842  
1186 1843  /*
1187 1844   * smbfs_access_rwx()
1188 1845   * Common function for smbfs_access, etc.
1189 1846   *
1190 1847   * The security model implemented by the FS is unusual
1191 1848   * due to the current "single user mounts" restriction:
1192 1849   * All access under a given mount point uses the CIFS
1193 1850   * credentials established by the owner of the mount.
1194 1851   *
1195 1852   * Most access checking is handled by the CIFS server,
1196 1853   * but we need sufficient Unix access checks here to
1197 1854   * prevent other local Unix users from having access
1198 1855   * to objects under this mount that the uid/gid/mode
1199 1856   * settings in the mount would not allow.
1200 1857   *
  
    | 
      ↓ 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          /*
1241 1892           * Disallow write attempts on read-only file systems,
1242 1893           * unless the file is a device or fifo node.  Note:
1243 1894           * Inline vn_is_readonly and IS_DEVVP here because
1244 1895           * we may not have a vnode ptr.  Original expr. was:
  
    | 
      ↓ 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,
1266 1916           * then check public access.
1267 1917           */
1268 1918          if (crgetuid(cr) != va.va_uid) {
1269 1919                  shift += 3;
1270 1920                  if (!groupmember(va.va_gid, cr))
1271 1921                          shift += 3;
1272 1922          }
1273 1923  
1274 1924          /*
1275 1925           * We need a vnode for secpolicy_vnode_access,
1276 1926           * but the only thing it looks at is v_type,
1277 1927           * so pass one of the templates above.
1278 1928           */
1279 1929          tvp = (va.va_type == VDIR) ?
1280 1930              (vnode_t *)&tmpl_vdir :
1281 1931              (vnode_t *)&tmpl_vreg;
1282 1932  
1283 1933          return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1284 1934              va.va_mode << shift, mode));
1285 1935  }
1286 1936  
1287 1937  /*
1288 1938   * See smbfs_setattr
1289 1939   */
1290 1940  static int
1291 1941  smbfs_accessx(void *arg, int mode, cred_t *cr)
1292 1942  {
1293 1943          vnode_t *vp = arg;
1294 1944          /*
1295 1945           * Note: The caller has checked the current zone,
1296 1946           * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1297 1947           */
1298 1948          return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1299 1949  }
1300 1950  
1301 1951  /*
1302 1952   * XXX
1303 1953   * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1304 1954   */
1305 1955  /* ARGSUSED */
1306 1956  static int
1307 1957  smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1308 1958  {
1309 1959          vfs_t           *vfsp;
1310 1960          smbmntinfo_t    *smi;
1311 1961  
1312 1962          vfsp = vp->v_vfsp;
1313 1963          smi = VFTOSMI(vfsp);
1314 1964  
  
    | 
      ↓ 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)
1335 1994  {
1336 1995          int             error = 0;
1337 1996          smbmntinfo_t    *smi;
1338 1997          smbnode_t       *np;
1339 1998          struct smb_cred scred;
1340 1999  
1341 2000          np = VTOSMB(vp);
1342 2001          smi = VTOSMI(vp);
1343 2002  
1344 2003          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1345 2004                  return (EIO);
  
    | 
      ↓ 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);
1406 2101          smb_credinit(&scred, cr);
1407 2102  
1408 2103          switch (np->n_ovtype) {
1409 2104          case VNON:
1410 2105                  /* not open (OK) */
1411 2106                  break;
1412 2107  
1413 2108          case VDIR:
1414 2109                  if (np->n_dirrefs == 0)
1415 2110                          break;
1416 2111                  SMBVDEBUG("open dir: refs %d path %s\n",
1417 2112                      np->n_dirrefs, np->n_rpath);
1418 2113                  /* Force last close. */
1419 2114                  np->n_dirrefs = 1;
1420 2115                  smbfs_rele_fid(np, &scred);
1421 2116                  break;
1422 2117  
1423 2118          case VREG:
1424 2119                  if (np->n_fidrefs == 0)
1425 2120                          break;
1426 2121                  SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1427 2122                      np->n_fidrefs, np->n_fid, np->n_rpath);
1428 2123                  /* Force last close. */
1429 2124                  np->n_fidrefs = 1;
1430 2125                  smbfs_rele_fid(np, &scred);
1431 2126                  break;
1432 2127  
1433 2128          default:
1434 2129                  SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1435 2130                  np->n_ovtype = VNON;
1436 2131                  break;
1437 2132          }
1438 2133  
1439 2134          smb_credrele(&scred);
1440 2135          smbfs_rw_exit(&np->r_lkserlock);
1441 2136  
1442 2137          /*
1443 2138           * XATTR directories (and the files under them) have
1444 2139           * little value for reclaim, so just remove them from
1445 2140           * the "hash" (AVL) as soon as they go inactive.
1446 2141           * Note that the node may already have been removed
1447 2142           * from the hash by smbfsremove.
1448 2143           */
1449 2144          if ((np->n_flag & N_XATTR) != 0 &&
1450 2145              (np->r_flags & RHASHED) != 0)
1451 2146                  smbfs_rmhash(np);
1452 2147  
1453 2148          smbfs_addfree(np);
1454 2149  }
1455 2150  
1456 2151  /*
1457 2152   * Remote file system operations having to do with directory manipulation.
1458 2153   */
1459 2154  /* ARGSUSED */
1460 2155  static int
1461 2156  smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1462 2157          int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1463 2158          int *direntflags, pathname_t *realpnp)
1464 2159  {
1465 2160          vfs_t           *vfs;
1466 2161          smbmntinfo_t    *smi;
1467 2162          smbnode_t       *dnp;
1468 2163          int             error;
1469 2164  
1470 2165          vfs = dvp->v_vfsp;
1471 2166          smi = VFTOSMI(vfs);
1472 2167  
1473 2168          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1474 2169                  return (EPERM);
1475 2170  
1476 2171          if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1477 2172                  return (EIO);
1478 2173  
1479 2174          dnp = VTOSMB(dvp);
1480 2175  
1481 2176          /*
1482 2177           * Are we looking up extended attributes?  If so, "dvp" is
1483 2178           * the file or directory for which we want attributes, and
1484 2179           * we need a lookup of the (faked up) attribute directory
1485 2180           * before we lookup the rest of the path.
1486 2181           */
1487 2182          if (flags & LOOKUP_XATTR) {
1488 2183                  /*
1489 2184                   * Require the xattr mount option.
1490 2185                   */
1491 2186                  if ((vfs->vfs_flag & VFS_XATTR) == 0)
1492 2187                          return (EINVAL);
1493 2188  
1494 2189                  error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1495 2190                  return (error);
1496 2191          }
1497 2192  
1498 2193          if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1499 2194                  return (EINTR);
1500 2195  
1501 2196          error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1502 2197  
1503 2198          smbfs_rw_exit(&dnp->r_rwlock);
1504 2199  
1505 2200          return (error);
1506 2201  }
1507 2202  
1508 2203  /* ARGSUSED */
1509 2204  static int
1510 2205  smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1511 2206          int cache_ok, caller_context_t *ct)
1512 2207  {
1513 2208          int             error;
1514 2209          int             supplen; /* supported length */
1515 2210          vnode_t         *vp;
1516 2211          smbnode_t       *np;
1517 2212          smbnode_t       *dnp;
1518 2213          smbmntinfo_t    *smi;
1519 2214          /* struct smb_vc        *vcp; */
1520 2215          const char      *ill;
1521 2216          const char      *name = (const char *)nm;
1522 2217          int             nmlen = strlen(nm);
1523 2218          int             rplen;
1524 2219          struct smb_cred scred;
1525 2220          struct smbfattr fa;
1526 2221  
1527 2222          smi = VTOSMI(dvp);
1528 2223          dnp = VTOSMB(dvp);
1529 2224  
1530 2225          ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1531 2226  
1532 2227  #ifdef NOT_YET
  
    | 
      ↓ 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;
1555 2248                  return (0);
1556 2249          }
1557 2250  
1558 2251          /*
1559 2252           * Can't do lookups in non-directories.
1560 2253           */
1561 2254          if (dvp->v_type != VDIR)
1562 2255                  return (ENOTDIR);
1563 2256  
1564 2257          /*
1565 2258           * Need search permission in the directory.
1566 2259           */
1567 2260          error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1568 2261          if (error)
1569 2262                  return (error);
1570 2263  
1571 2264          /*
1572 2265           * If lookup is for ".", just return dvp.
1573 2266           * Access check was done above.
1574 2267           */
1575 2268          if (nmlen == 1 && name[0] == '.') {
1576 2269                  VN_HOLD(dvp);
1577 2270                  *vpp = dvp;
1578 2271                  return (0);
1579 2272          }
1580 2273  
  
    | 
      ↓ 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           *
1602 2295           * We keep full pathnames (as seen on the server)
1603 2296           * so we can just trim off the last component to
1604 2297           * get the full pathname of the parent.  Note:
1605 2298           * We don't actually copy and modify, but just
1606 2299           * compute the trimmed length and pass that with
1607 2300           * the current dir path (not null terminated).
1608 2301           *
1609 2302           * We don't go over-the-wire to get attributes
1610 2303           * for ".." because we know it's a directory,
1611 2304           * and we can just leave the rest "stale"
1612 2305           * until someone does a getattr.
1613 2306           */
1614 2307          if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1615 2308                  if (dvp->v_flag & VROOT) {
1616 2309                          /*
1617 2310                           * Already at the root.  This can happen
1618 2311                           * with directory listings at the root,
1619 2312                           * which lookup "." and ".." to get the
1620 2313                           * inode numbers.  Let ".." be the same
1621 2314                           * as "." in the FS root.
1622 2315                           */
1623 2316                          VN_HOLD(dvp);
1624 2317                          *vpp = dvp;
1625 2318                          return (0);
1626 2319                  }
1627 2320  
1628 2321                  /*
1629 2322                   * Special case for XATTR directory
1630 2323                   */
1631 2324                  if (dvp->v_flag & V_XATTRDIR) {
1632 2325                          error = smbfs_xa_parent(dvp, vpp);
1633 2326                          return (error);
1634 2327                  }
1635 2328  
1636 2329                  /*
1637 2330                   * Find the parent path length.
1638 2331                   */
1639 2332                  rplen = dnp->n_rplen;
1640 2333                  ASSERT(rplen > 0);
1641 2334                  while (--rplen >= 0) {
1642 2335                          if (dnp->n_rpath[rplen] == '\\')
1643 2336                                  break;
1644 2337                  }
1645 2338                  if (rplen <= 0) {
1646 2339                          /* Found our way to the root. */
1647 2340                          vp = SMBTOV(smi->smi_root);
1648 2341                          VN_HOLD(vp);
1649 2342                          *vpp = vp;
1650 2343                          return (0);
1651 2344                  }
1652 2345                  np = smbfs_node_findcreate(smi,
1653 2346                      dnp->n_rpath, rplen, NULL, 0, 0,
1654 2347                      &smbfs_fattr0); /* force create */
1655 2348                  ASSERT(np != NULL);
1656 2349                  vp = SMBTOV(np);
1657 2350                  vp->v_type = VDIR;
1658 2351  
1659 2352                  /* Success! */
1660 2353                  *vpp = vp;
1661 2354                  return (0);
1662 2355          }
1663 2356  
1664 2357          /*
1665 2358           * Normal lookup of a name under this directory.
1666 2359           * Note we handled "", ".", ".." above.
1667 2360           */
1668 2361          if (cache_ok) {
1669 2362                  /*
1670 2363                   * The caller indicated that it's OK to use a
1671 2364                   * cached result for this lookup, so try to
1672 2365                   * reclaim a node from the smbfs node cache.
1673 2366                   */
1674 2367                  error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1675 2368                  if (error)
1676 2369                          return (error);
1677 2370                  if (vp != NULL) {
1678 2371                          /* hold taken in lookup_cache */
1679 2372                          *vpp = vp;
1680 2373                          return (0);
1681 2374                  }
1682 2375          }
1683 2376  
1684 2377          /*
1685 2378           * OK, go over-the-wire to get the attributes,
1686 2379           * then create the node.
1687 2380           */
1688 2381          smb_credinit(&scred, cr);
1689 2382          /* Note: this can allocate a new "name" */
1690 2383          error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1691 2384          smb_credrele(&scred);
1692 2385          if (error == ENOTDIR) {
1693 2386                  /*
1694 2387                   * Lookup failed because this directory was
1695 2388                   * removed or renamed by another client.
1696 2389                   * Remove any cached attributes under it.
1697 2390                   */
1698 2391                  smbfs_attrcache_remove(dnp);
1699 2392                  smbfs_attrcache_prune(dnp);
1700 2393          }
1701 2394          if (error)
1702 2395                  goto out;
1703 2396  
1704 2397          error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1705 2398          if (error)
1706 2399                  goto out;
1707 2400  
1708 2401          /* Success! */
1709 2402          *vpp = vp;
1710 2403  
1711 2404  out:
1712 2405          /* smbfs_smb_lookup may have allocated name. */
1713 2406          if (name != nm)
1714 2407                  smbfs_name_free(name, nmlen);
1715 2408  
1716 2409          return (error);
1717 2410  }
1718 2411  
1719 2412  /*
1720 2413   * smbfslookup_cache
1721 2414   *
1722 2415   * Try to reclaim a node from the smbfs node cache.
1723 2416   * Some statistics for DEBUG.
1724 2417   *
1725 2418   * This mechanism lets us avoid many of the five (or more)
1726 2419   * OtW lookup calls per file seen with "ls -l" if we search
1727 2420   * the smbfs node cache for recently inactive(ated) nodes.
1728 2421   */
1729 2422  #ifdef DEBUG
1730 2423  int smbfs_lookup_cache_calls = 0;
1731 2424  int smbfs_lookup_cache_error = 0;
1732 2425  int smbfs_lookup_cache_miss = 0;
1733 2426  int smbfs_lookup_cache_stale = 0;
1734 2427  int smbfs_lookup_cache_hits = 0;
1735 2428  #endif /* DEBUG */
1736 2429  
1737 2430  /* ARGSUSED */
1738 2431  static int
1739 2432  smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1740 2433          vnode_t **vpp, cred_t *cr)
1741 2434  {
1742 2435          struct vattr va;
1743 2436          smbnode_t *dnp;
1744 2437          smbnode_t *np;
1745 2438          vnode_t *vp;
1746 2439          int error;
1747 2440          char sep;
1748 2441  
1749 2442          dnp = VTOSMB(dvp);
1750 2443          *vpp = NULL;
1751 2444  
1752 2445  #ifdef DEBUG
1753 2446          smbfs_lookup_cache_calls++;
1754 2447  #endif
1755 2448  
1756 2449          /*
1757 2450           * First make sure we can get attributes for the
1758 2451           * directory.  Cached attributes are OK here.
1759 2452           * If we removed or renamed the directory, this
1760 2453           * will return ENOENT.  If someone else removed
1761 2454           * this directory or file, we'll find out when we
1762 2455           * try to open or get attributes.
1763 2456           */
1764 2457          va.va_mask = AT_TYPE | AT_MODE;
1765 2458          error = smbfsgetattr(dvp, &va, cr);
1766 2459          if (error) {
1767 2460  #ifdef DEBUG
1768 2461                  smbfs_lookup_cache_error++;
1769 2462  #endif
1770 2463                  return (error);
1771 2464          }
1772 2465  
1773 2466          /*
1774 2467           * Passing NULL smbfattr here so we will
1775 2468           * just look, not create.
1776 2469           */
1777 2470          sep = SMBFS_DNP_SEP(dnp);
1778 2471          np = smbfs_node_findcreate(dnp->n_mount,
1779 2472              dnp->n_rpath, dnp->n_rplen,
1780 2473              nm, nmlen, sep, NULL);
1781 2474          if (np == NULL) {
1782 2475  #ifdef DEBUG
1783 2476                  smbfs_lookup_cache_miss++;
1784 2477  #endif
1785 2478                  return (0);
1786 2479          }
1787 2480  
1788 2481          /*
1789 2482           * Found it.  Attributes still valid?
1790 2483           */
1791 2484          vp = SMBTOV(np);
1792 2485          if (np->r_attrtime <= gethrtime()) {
1793 2486                  /* stale */
1794 2487  #ifdef DEBUG
1795 2488                  smbfs_lookup_cache_stale++;
1796 2489  #endif
1797 2490                  VN_RELE(vp);
1798 2491                  return (0);
1799 2492          }
1800 2493  
1801 2494          /*
  
    | 
      ↓ 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;
1843 2535  
1844 2536          vfsp = dvp->v_vfsp;
1845 2537          smi = VFTOSMI(vfsp);
1846 2538          dnp = VTOSMB(dvp);
1847 2539          vp = NULL;
  
    | 
      ↓ 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);
1869 2561                  *vpp = dvp;
1870 2562                  return (0);
1871 2563          }
1872 2564  
1873 2565          /* Don't allow "." or ".." through here. */
1874 2566          if ((nmlen == 1 && name[0] == '.') ||
1875 2567              (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1876 2568                  return (EISDIR);
1877 2569  
1878 2570          /*
1879 2571           * We make a copy of the attributes because the caller does not
1880 2572           * expect us to change what va points to.
1881 2573           */
1882 2574          vattr = *va;
1883 2575  
1884 2576          if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1885 2577                  return (EINTR);
1886 2578          smb_credinit(&scred, cr);
1887 2579  
1888 2580          /*
1889 2581           * NFS needs to go over the wire, just to be sure whether the
1890 2582           * file exists or not.  Using a cached result is dangerous in
1891 2583           * this case when making a decision regarding existence.
1892 2584           *
1893 2585           * The SMB protocol does NOT really need to go OTW here
1894 2586           * thanks to the expressive NTCREATE disposition values.
1895 2587           * Unfortunately, to do Unix access checks correctly,
1896 2588           * we need to know if the object already exists.
1897 2589           * When the object does not exist, we need VWRITE on
1898 2590           * the directory.  Note: smbfslookup() checks VEXEC.
1899 2591           */
1900 2592          error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1901 2593          if (error == 0) {
1902 2594                  /*
1903 2595                   * The file already exists.  Error?
1904 2596                   * NB: have a hold from smbfslookup
1905 2597                   */
1906 2598                  if (exclusive == EXCL) {
1907 2599                          error = EEXIST;
1908 2600                          VN_RELE(vp);
1909 2601                          goto out;
1910 2602                  }
1911 2603                  /*
1912 2604                   * Verify requested access.
  
    | 
      ↓ 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;
1945 2654  
1946 2655          /*
1947 2656           * Now things get tricky.  We also need to check the
1948 2657           * requested open mode against the file we may create.
1949 2658           * See comments at smbfs_access_rwx
1950 2659           */
1951 2660          error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1952 2661          if (error)
1953 2662                  goto out;
1954 2663  
1955 2664          /*
1956 2665           * Now the code derived from Darwin,
1957 2666           * but with greater use of NT_CREATE
1958 2667           * disposition options.  Much changed.
1959 2668           *
1960 2669           * Create (or open) a new child node.
1961 2670           * Note we handled "." and ".." above.
1962 2671           */
1963 2672  
1964 2673          if (exclusive == EXCL)
1965 2674                  disp = NTCREATEX_DISP_CREATE;
1966 2675          else {
1967 2676                  /* Truncate regular files if requested. */
1968 2677                  if ((va->va_type == VREG) &&
1969 2678                      (va->va_mask & AT_SIZE) &&
1970 2679                      (va->va_size == 0))
1971 2680                          disp = NTCREATEX_DISP_OVERWRITE_IF;
1972 2681                  else
  
    | 
      ↓ 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          /*
2023 2702           * In the open case, the name may differ a little
2024 2703           * from what we passed to create (case, etc.)
2025 2704           * so call lookup to get the (opened) name.
2026 2705           *
2027 2706           * XXX: Could avoid this extra lookup if the
2028 2707           * "createact" result from NT_CREATE says we
2029 2708           * created the object.
2030 2709           */
2031 2710          error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
  
    | 
      ↓ 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);
2054 2731  }
2055 2732  
2056 2733  /*
2057 2734   * XXX
2058 2735   * This op should support the new FIGNORECASE flag for case-insensitive
2059 2736   * lookups, per PSARC 2007/244.
2060 2737   */
2061 2738  /* ARGSUSED */
2062 2739  static int
2063 2740  smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
2064 2741          int flags)
2065 2742  {
2066 2743          struct smb_cred scred;
2067 2744          vnode_t         *vp = NULL;
2068 2745          smbnode_t       *dnp = VTOSMB(dvp);
2069 2746          smbmntinfo_t    *smi = VTOSMI(dvp);
2070 2747          int             error;
2071 2748  
2072 2749          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2073 2750                  return (EPERM);
2074 2751  
2075 2752          if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2076 2753                  return (EIO);
2077 2754  
2078 2755          /*
2079 2756           * Verify access to the dirctory.
2080 2757           */
2081 2758          error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2082 2759          if (error)
2083 2760                  return (error);
2084 2761  
2085 2762          if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2086 2763                  return (EINTR);
2087 2764          smb_credinit(&scred, cr);
2088 2765  
2089 2766          /* Lookup the file to remove. */
2090 2767          error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2091 2768          if (error == 0) {
2092 2769                  /*
2093 2770                   * Do the real remove work
2094 2771                   */
2095 2772                  error = smbfsremove(dvp, vp, &scred, flags);
2096 2773                  VN_RELE(vp);
2097 2774          }
2098 2775  
2099 2776          smb_credrele(&scred);
2100 2777          smbfs_rw_exit(&dnp->r_rwlock);
2101 2778  
2102 2779          return (error);
2103 2780  }
2104 2781  
2105 2782  /*
2106 2783   * smbfsremove does the real work of removing in SMBFS
2107 2784   * Caller has done dir access checks etc.
2108 2785   *
2109 2786   * The normal way to delete a file over SMB is open it (with DELETE access),
2110 2787   * set the "delete-on-close" flag, and close the file.  The problem for Unix
2111 2788   * applications is that they expect the file name to be gone once the unlink
2112 2789   * completes, and the SMB server does not actually delete the file until ALL
2113 2790   * opens of that file are closed.  We can't assume our open handles are the
2114 2791   * only open handles on a file we're deleting, so to be safe we'll try to
2115 2792   * rename the file to a temporary name and then set delete-on-close.  If we
2116 2793   * fail to set delete-on-close (i.e. because other opens prevent it) then
2117 2794   * undo the changes we made and give up with EBUSY.  Note that we might have
2118 2795   * permission to delete a file but lack permission to rename, so we want to
2119 2796   * continue in cases where rename fails.  As an optimization, only do the
2120 2797   * rename when we have the file open.
2121 2798   *
2122 2799   * This is similar to what NFS does when deleting a file that has local opens,
2123 2800   * but thanks to SMB delete-on-close, we don't need to keep track of when the
2124 2801   * last local open goes away and send a delete.  The server does that for us.
2125 2802   */
2126 2803  /* ARGSUSED */
2127 2804  static int
2128 2805  smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
2129 2806      int flags)
2130 2807  {
2131 2808          smbnode_t       *dnp = VTOSMB(dvp);
2132 2809          smbnode_t       *np = VTOSMB(vp);
2133 2810          char            *tmpname = NULL;
2134 2811          int             tnlen;
2135 2812          int             error;
2136 2813          unsigned short  fid;
2137 2814          boolean_t       have_fid = B_FALSE;
2138 2815          boolean_t       renamed = B_FALSE;
  
    | 
      ↓ 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;
2166 2858          }
2167 2859          have_fid = B_TRUE;
2168 2860  
  
    | 
      ↓ 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           */
2190 2882          error = smbfs_smb_setdisp(np, fid, 1, scred);
2191 2883          if (error != 0) {
2192 2884                  SMBVDEBUG("error %d setting DoC on %s\n",
2193 2885                      error, np->n_rpath);
2194 2886                  /*
2195 2887                   * Failed to set DoC. If we renamed, undo that.
2196 2888                   * Need np->n_rpath relative to parent (dnp).
2197 2889                   * Use parent path name length plus one for
2198 2890                   * the separator ('/' or ':')
2199 2891                   */
  
    | 
      ↓ 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  {
2245 2951          struct smb_cred scred;
2246 2952          smbnode_t       *odnp = VTOSMB(odvp);
2247 2953          smbnode_t       *ndnp = VTOSMB(ndvp);
2248 2954          vnode_t         *ovp;
2249 2955          int error;
2250 2956  
2251 2957          if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2252 2958              curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2253 2959                  return (EPERM);
2254 2960  
2255 2961          if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2256 2962              VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2257 2963              odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2258 2964              ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2259 2965                  return (EIO);
2260 2966  
2261 2967          if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2262 2968              strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2263 2969                  return (EINVAL);
2264 2970  
2265 2971          /*
2266 2972           * Check that everything is on the same filesystem.
2267 2973           * vn_rename checks the fsid's, but in case we don't
2268 2974           * fill those in correctly, check here too.
2269 2975           */
2270 2976          if (odvp->v_vfsp != ndvp->v_vfsp)
2271 2977                  return (EXDEV);
2272 2978  
2273 2979          /*
2274 2980           * Need write access on source and target.
2275 2981           * Server takes care of most checks.
2276 2982           */
2277 2983          error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2278 2984          if (error)
2279 2985                  return (error);
2280 2986          if (odvp != ndvp) {
2281 2987                  error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2282 2988                  if (error)
2283 2989                          return (error);
2284 2990          }
2285 2991  
2286 2992          /*
2287 2993           * Need to lock both old/new dirs as writer.
2288 2994           *
2289 2995           * Avoid deadlock here on old vs new directory nodes
2290 2996           * by always taking the locks in order of address.
2291 2997           * The order is arbitrary, but must be consistent.
2292 2998           */
2293 2999          if (odnp < ndnp) {
2294 3000                  if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2295 3001                      SMBINTR(odvp)))
2296 3002                          return (EINTR);
2297 3003                  if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2298 3004                      SMBINTR(ndvp))) {
2299 3005                          smbfs_rw_exit(&odnp->r_rwlock);
2300 3006                          return (EINTR);
2301 3007                  }
2302 3008          } else {
2303 3009                  if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2304 3010                      SMBINTR(ndvp)))
2305 3011                          return (EINTR);
2306 3012                  if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2307 3013                      SMBINTR(odvp))) {
2308 3014                          smbfs_rw_exit(&ndnp->r_rwlock);
2309 3015                          return (EINTR);
2310 3016                  }
2311 3017          }
2312 3018          smb_credinit(&scred, cr);
2313 3019  
2314 3020          /* Lookup the "old" name */
2315 3021          error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2316 3022          if (error == 0) {
2317 3023                  /*
2318 3024                   * Do the real rename work
2319 3025                   */
2320 3026                  error = smbfsrename(odvp, ovp, ndvp, nnm, &scred, flags);
2321 3027                  VN_RELE(ovp);
2322 3028          }
2323 3029  
2324 3030          smb_credrele(&scred);
2325 3031          smbfs_rw_exit(&odnp->r_rwlock);
2326 3032          smbfs_rw_exit(&ndnp->r_rwlock);
2327 3033  
2328 3034          return (error);
2329 3035  }
2330 3036  
2331 3037  /*
2332 3038   * smbfsrename does the real work of renaming in SMBFS
2333 3039   * Caller has done dir access checks etc.
2334 3040   */
2335 3041  /* ARGSUSED */
2336 3042  static int
2337 3043  smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
2338 3044      struct smb_cred *scred, int flags)
2339 3045  {
2340 3046          smbnode_t       *odnp = VTOSMB(odvp);
2341 3047          smbnode_t       *onp = VTOSMB(ovp);
2342 3048          smbnode_t       *ndnp = VTOSMB(ndvp);
2343 3049          vnode_t         *nvp = NULL;
2344 3050          int             error;
2345 3051          int             nvp_locked = 0;
2346 3052  
2347 3053          /* Things our caller should have checked. */
2348 3054          ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2349 3055          ASSERT(odvp->v_vfsp == ndvp->v_vfsp);
2350 3056          ASSERT(odnp->r_rwlock.owner == curthread);
2351 3057          ASSERT(ndnp->r_rwlock.owner == curthread);
2352 3058  
2353 3059          /*
2354 3060           * Lookup the target file.  If it exists, it needs to be
2355 3061           * checked to see whether it is a mount point and whether
2356 3062           * it is active (open).
2357 3063           */
2358 3064          error = smbfslookup(ndvp, nnm, &nvp, scred->scr_cred, 0, NULL);
2359 3065          if (!error) {
2360 3066                  /*
2361 3067                   * Target (nvp) already exists.  Check that it
2362 3068                   * has the same type as the source.  The server
2363 3069                   * will check this also, (and more reliably) but
2364 3070                   * this lets us return the correct error codes.
2365 3071                   */
2366 3072                  if (ovp->v_type == VDIR) {
2367 3073                          if (nvp->v_type != VDIR) {
2368 3074                                  error = ENOTDIR;
2369 3075                                  goto out;
2370 3076                          }
2371 3077                  } else {
2372 3078                          if (nvp->v_type == VDIR) {
2373 3079                                  error = EISDIR;
2374 3080                                  goto out;
2375 3081                          }
2376 3082                  }
2377 3083  
2378 3084                  /*
2379 3085                   * POSIX dictates that when the source and target
2380 3086                   * entries refer to the same file object, rename
2381 3087                   * must do nothing and exit without error.
2382 3088                   */
2383 3089                  if (ovp == nvp) {
2384 3090                          error = 0;
2385 3091                          goto out;
2386 3092                  }
2387 3093  
2388 3094                  /*
2389 3095                   * Also must ensure the target is not a mount point,
2390 3096                   * and keep mount/umount away until we're done.
2391 3097                   */
2392 3098                  if (vn_vfsrlock(nvp)) {
2393 3099                          error = EBUSY;
2394 3100                          goto out;
2395 3101                  }
2396 3102                  nvp_locked = 1;
2397 3103                  if (vn_mountedvfs(nvp) != NULL) {
2398 3104                          error = EBUSY;
2399 3105                          goto out;
2400 3106                  }
2401 3107  
2402 3108                  /*
2403 3109                   * CIFS may give a SHARING_VIOLATION error when
2404 3110                   * trying to rename onto an exising object,
2405 3111                   * so try to remove the target first.
2406 3112                   * (Only for files, not directories.)
2407 3113                   */
2408 3114                  if (nvp->v_type == VDIR) {
2409 3115                          error = EEXIST;
2410 3116                          goto out;
2411 3117                  }
2412 3118                  error = smbfsremove(ndvp, nvp, scred, flags);
2413 3119                  if (error != 0)
2414 3120                          goto out;
2415 3121  
2416 3122                  /*
  
    | 
      ↓ 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  }
2446 3153  
2447 3154  /*
2448 3155   * XXX
2449 3156   * vsecattr_t is new to build 77, and we need to eventually support
2450 3157   * it in order to create an ACL when an object is created.
2451 3158   *
2452 3159   * This op should support the new FIGNORECASE flag for case-insensitive
2453 3160   * lookups, per PSARC 2007/244.
2454 3161   */
2455 3162  /* ARGSUSED */
2456 3163  static int
2457 3164  smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2458 3165          cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2459 3166  {
2460 3167          vnode_t         *vp;
2461 3168          struct smbnode  *dnp = VTOSMB(dvp);
2462 3169          struct smbmntinfo *smi = VTOSMI(dvp);
2463 3170          struct smb_cred scred;
2464 3171          struct smbfattr fattr;
2465 3172          const char              *name = (const char *) nm;
2466 3173          int             nmlen = strlen(name);
2467 3174          int             error, hiderr;
2468 3175  
2469 3176          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2470 3177                  return (EPERM);
2471 3178  
2472 3179          if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2473 3180                  return (EIO);
2474 3181  
2475 3182          if ((nmlen == 1 && name[0] == '.') ||
2476 3183              (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2477 3184                  return (EEXIST);
  
    | 
      ↓ 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  
2503 3205          error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2504 3206          if (error)
2505 3207                  goto out;
2506 3208  
2507 3209          smbfs_attr_touchdir(dnp);
2508 3210  
2509 3211          error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2510 3212          if (error)
2511 3213                  goto out;
2512 3214  
2513 3215          if (name[0] == '.')
2514 3216                  if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2515 3217                          SMBVDEBUG("hide failure %d\n", hiderr);
2516 3218  
2517 3219          /* Success! */
2518 3220          *vpp = vp;
2519 3221          error = 0;
2520 3222  out:
2521 3223          smb_credrele(&scred);
2522 3224          smbfs_rw_exit(&dnp->r_rwlock);
2523 3225  
2524 3226          if (name != nm)
2525 3227                  smbfs_name_free(name, nmlen);
2526 3228  
2527 3229          return (error);
2528 3230  }
2529 3231  
2530 3232  /*
2531 3233   * XXX
2532 3234   * This op should support the new FIGNORECASE flag for case-insensitive
2533 3235   * lookups, per PSARC 2007/244.
2534 3236   */
2535 3237  /* ARGSUSED */
2536 3238  static int
2537 3239  smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2538 3240          caller_context_t *ct, int flags)
2539 3241  {
2540 3242          vnode_t         *vp = NULL;
2541 3243          int             vp_locked = 0;
2542 3244          struct smbmntinfo *smi = VTOSMI(dvp);
2543 3245          struct smbnode  *dnp = VTOSMB(dvp);
2544 3246          struct smbnode  *np;
2545 3247          struct smb_cred scred;
2546 3248          int             error;
2547 3249  
2548 3250          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2549 3251                  return (EPERM);
2550 3252  
2551 3253          if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2552 3254                  return (EIO);
2553 3255  
2554 3256          if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2555 3257                  return (EINTR);
2556 3258          smb_credinit(&scred, cr);
2557 3259  
2558 3260          /*
2559 3261           * Require w/x access in the containing directory.
2560 3262           * Server handles all other access checks.
2561 3263           */
2562 3264          error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2563 3265          if (error)
2564 3266                  goto out;
2565 3267  
2566 3268          /*
2567 3269           * First lookup the entry to be removed.
2568 3270           */
2569 3271          error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2570 3272          if (error)
2571 3273                  goto out;
2572 3274          np = VTOSMB(vp);
2573 3275  
2574 3276          /*
2575 3277           * Disallow rmdir of "." or current dir, or the FS root.
2576 3278           * Also make sure it's a directory, not a mount point,
2577 3279           * and lock to keep mount/umount away until we're done.
2578 3280           */
2579 3281          if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2580 3282                  error = EINVAL;
2581 3283                  goto out;
2582 3284          }
2583 3285          if (vp->v_type != VDIR) {
2584 3286                  error = ENOTDIR;
2585 3287                  goto out;
2586 3288          }
2587 3289          if (vn_vfsrlock(vp)) {
2588 3290                  error = EBUSY;
2589 3291                  goto out;
2590 3292          }
2591 3293          vp_locked = 1;
2592 3294          if (vn_mountedvfs(vp) != NULL) {
2593 3295                  error = EBUSY;
2594 3296                  goto out;
2595 3297          }
2596 3298  
2597 3299          smbfs_attrcache_remove(np);
2598 3300          error = smbfs_smb_rmdir(np, &scred);
2599 3301  
2600 3302          /*
2601 3303           * Similar to smbfs_remove
2602 3304           */
2603 3305          switch (error) {
2604 3306          case 0:
2605 3307          case ENOENT:
2606 3308          case ENOTDIR:
2607 3309                  smbfs_attrcache_prune(np);
2608 3310                  break;
2609 3311          }
2610 3312  
2611 3313          if (error)
2612 3314                  goto out;
2613 3315  
2614 3316          mutex_enter(&np->r_statelock);
2615 3317          dnp->n_flag |= NMODIFIED;
2616 3318          mutex_exit(&np->r_statelock);
2617 3319          smbfs_attr_touchdir(dnp);
2618 3320          smbfs_rmhash(np);
2619 3321  
2620 3322  out:
2621 3323          if (vp) {
2622 3324                  if (vp_locked)
2623 3325                          vn_vfsunlock(vp);
2624 3326                  VN_RELE(vp);
  
    | 
      ↓ 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)
2645 3357                  return (EIO);
2646 3358  
2647 3359          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2648 3360                  return (EIO);
2649 3361  
  
    | 
      ↓ 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);
2672 3383  
2673 3384          smbfs_rw_exit(&np->r_lkserlock);
2674 3385  
2675 3386          return (error);
2676 3387  }
2677 3388  
2678 3389  /* ARGSUSED */
2679 3390  static int
2680 3391  smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2681 3392          caller_context_t *ct)
2682 3393  {
2683 3394          /*
2684 3395           * Note: "limit" tells the SMB-level FindFirst/FindNext
2685 3396           * functions how many directory entries to request in
2686 3397           * each OtW call.  It needs to be large enough so that
2687 3398           * we don't make lots of tiny OtW requests, but there's
2688 3399           * no point making it larger than the maximum number of
2689 3400           * OtW entries that would fit in a maximum sized trans2
2690 3401           * response (64k / 48).  Beyond that, it's just tuning.
2691 3402           * WinNT used 512, Win2k used 1366.  We use 1000.
2692 3403           */
2693 3404          static const int limit = 1000;
2694 3405          /* Largest possible dirent size. */
2695 3406          static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2696 3407          struct smb_cred scred;
2697 3408          vnode_t         *newvp;
2698 3409          struct smbnode  *np = VTOSMB(vp);
2699 3410          struct smbfs_fctx *ctx;
2700 3411          struct dirent64 *dp;
2701 3412          ssize_t         save_resid;
2702 3413          offset_t        save_offset; /* 64 bits */
2703 3414          int             offset; /* yes, 32 bits */
2704 3415          int             nmlen, error;
2705 3416          ushort_t        reclen;
2706 3417  
2707 3418          ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2708 3419  
2709 3420          /* Make sure we serialize for n_dirseq use. */
2710 3421          ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2711 3422  
2712 3423          /*
2713 3424           * Make sure smbfs_open filled in n_dirseq
2714 3425           */
2715 3426          if (np->n_dirseq == NULL)
2716 3427                  return (EBADF);
2717 3428  
2718 3429          /* Check for overflow of (32-bit) directory offset. */
2719 3430          if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2720 3431              (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2721 3432                  return (EINVAL);
2722 3433  
2723 3434          /* Require space for at least one dirent. */
2724 3435          if (uio->uio_resid < dbufsiz)
2725 3436                  return (EINVAL);
2726 3437  
2727 3438          SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2728 3439          smb_credinit(&scred, cr);
2729 3440          dp = kmem_alloc(dbufsiz, KM_SLEEP);
2730 3441  
2731 3442          save_resid = uio->uio_resid;
2732 3443          save_offset = uio->uio_loffset;
2733 3444          offset = uio->uio_offset;
2734 3445          SMBVDEBUG("in: offset=%d, resid=%d\n",
2735 3446              (int)uio->uio_offset, (int)uio->uio_resid);
2736 3447          error = 0;
2737 3448  
2738 3449          /*
2739 3450           * Generate the "." and ".." entries here so we can
2740 3451           * (1) make sure they appear (but only once), and
2741 3452           * (2) deal with getting their I numbers which the
2742 3453           * findnext below does only for normal names.
2743 3454           */
2744 3455          while (offset < FIRST_DIROFS) {
2745 3456                  /*
2746 3457                   * Tricky bit filling in the first two:
2747 3458                   * offset 0 is ".", offset 1 is ".."
2748 3459                   * so strlen of these is offset+1.
2749 3460                   */
2750 3461                  reclen = DIRENT64_RECLEN(offset + 1);
2751 3462                  if (uio->uio_resid < reclen)
2752 3463                          goto out;
2753 3464                  bzero(dp, reclen);
2754 3465                  dp->d_reclen = reclen;
2755 3466                  dp->d_name[0] = '.';
2756 3467                  dp->d_name[1] = '.';
2757 3468                  dp->d_name[offset + 1] = '\0';
2758 3469                  /*
2759 3470                   * Want the real I-numbers for the "." and ".."
2760 3471                   * entries.  For these two names, we know that
2761 3472                   * smbfslookup can get the nodes efficiently.
2762 3473                   */
2763 3474                  error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2764 3475                  if (error) {
2765 3476                          dp->d_ino = np->n_ino + offset; /* fiction */
2766 3477                  } else {
2767 3478                          dp->d_ino = VTOSMB(newvp)->n_ino;
2768 3479                          VN_RELE(newvp);
2769 3480                  }
2770 3481                  /*
2771 3482                   * Note: d_off is the offset that a user-level program
2772 3483                   * should seek to for reading the NEXT directory entry.
2773 3484                   * See libc: readdir, telldir, seekdir
2774 3485                   */
2775 3486                  dp->d_off = offset + 1;
2776 3487                  error = uiomove(dp, reclen, UIO_READ, uio);
2777 3488                  if (error)
2778 3489                          goto out;
2779 3490                  /*
2780 3491                   * Note: uiomove updates uio->uio_offset,
2781 3492                   * but we want it to be our "cookie" value,
2782 3493                   * which just counts dirents ignoring size.
2783 3494                   */
2784 3495                  uio->uio_offset = ++offset;
2785 3496          }
2786 3497  
2787 3498          /*
2788 3499           * If there was a backward seek, we have to reopen.
2789 3500           */
2790 3501          if (offset < np->n_dirofs) {
2791 3502                  SMBVDEBUG("Reopening search %d:%d\n",
2792 3503                      offset, np->n_dirofs);
2793 3504                  error = smbfs_smb_findopen(np, "*", 1,
2794 3505                      SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2795 3506                      &scred, &ctx);
2796 3507                  if (error) {
2797 3508                          SMBVDEBUG("can not open search, error = %d", error);
2798 3509                          goto out;
2799 3510                  }
2800 3511                  /* free the old one */
2801 3512                  (void) smbfs_smb_findclose(np->n_dirseq, &scred);
2802 3513                  /* save the new one */
2803 3514                  np->n_dirseq = ctx;
2804 3515                  np->n_dirofs = FIRST_DIROFS;
2805 3516          } else {
2806 3517                  ctx = np->n_dirseq;
2807 3518          }
2808 3519  
2809 3520          /*
2810 3521           * Skip entries before the requested offset.
2811 3522           */
2812 3523          while (np->n_dirofs < offset) {
2813 3524                  error = smbfs_smb_findnext(ctx, limit, &scred);
2814 3525                  if (error != 0)
2815 3526                          goto out;
2816 3527                  np->n_dirofs++;
2817 3528          }
2818 3529  
2819 3530          /*
2820 3531           * While there's room in the caller's buffer:
2821 3532           *      get a directory entry from SMB,
2822 3533           *      convert to a dirent, copyout.
2823 3534           * We stop when there is no longer room for a
2824 3535           * maximum sized dirent because we must decide
2825 3536           * before we know anything about the next entry.
2826 3537           */
2827 3538          while (uio->uio_resid >= dbufsiz) {
2828 3539                  error = smbfs_smb_findnext(ctx, limit, &scred);
2829 3540                  if (error != 0)
2830 3541                          goto out;
2831 3542                  np->n_dirofs++;
2832 3543  
2833 3544                  /* Sanity check the name length. */
2834 3545                  nmlen = ctx->f_nmlen;
2835 3546                  if (nmlen > SMB_MAXFNAMELEN) {
2836 3547                          nmlen = SMB_MAXFNAMELEN;
2837 3548                          SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2838 3549                  }
2839 3550                  if (smbfs_fastlookup) {
2840 3551                          /* See comment at smbfs_fastlookup above. */
2841 3552                          if (smbfs_nget(vp, ctx->f_name, nmlen,
2842 3553                              &ctx->f_attr, &newvp) == 0)
2843 3554                                  VN_RELE(newvp);
2844 3555                  }
2845 3556  
2846 3557                  reclen = DIRENT64_RECLEN(nmlen);
2847 3558                  bzero(dp, reclen);
2848 3559                  dp->d_reclen = reclen;
2849 3560                  bcopy(ctx->f_name, dp->d_name, nmlen);
2850 3561                  dp->d_name[nmlen] = '\0';
2851 3562                  dp->d_ino = ctx->f_inum;
2852 3563                  dp->d_off = offset + 1; /* See d_off comment above */
2853 3564                  error = uiomove(dp, reclen, UIO_READ, uio);
2854 3565                  if (error)
2855 3566                          goto out;
2856 3567                  /* See comment re. uio_offset above. */
2857 3568                  uio->uio_offset = ++offset;
2858 3569          }
2859 3570  
2860 3571  out:
2861 3572          /*
2862 3573           * When we come to the end of a directory, the
2863 3574           * SMB-level functions return ENOENT, but the
2864 3575           * caller is not expecting an error return.
2865 3576           *
2866 3577           * Also note that we must delay the call to
2867 3578           * smbfs_smb_findclose(np->n_dirseq, ...)
2868 3579           * until smbfs_close so that all reads at the
2869 3580           * end of the directory will return no data.
2870 3581           */
2871 3582          if (error == ENOENT) {
2872 3583                  error = 0;
2873 3584                  if (eofp)
2874 3585                          *eofp = 1;
2875 3586          }
2876 3587          /*
2877 3588           * If we encountered an error (i.e. "access denied")
2878 3589           * from the FindFirst call, we will have copied out
2879 3590           * the "." and ".." entries leaving offset == 2.
2880 3591           * In that case, restore the original offset/resid
2881 3592           * so the caller gets no data with the error.
2882 3593           */
2883 3594          if (error != 0 && offset == FIRST_DIROFS) {
2884 3595                  uio->uio_loffset = save_offset;
  
    | 
      ↓ 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!
2906 3629   * In fact, the return value from _rwlock is NOT
2907 3630   * an error code, but V_WRITELOCK_TRUE / _FALSE.
2908 3631   *
2909 3632   * Therefore, it's up to _this_ code to make sure
2910 3633   * the lock state remains balanced, which means
2911 3634   * we can't "bail out" on interrupts, etc.
2912 3635   */
2913 3636  
2914 3637  /* ARGSUSED2 */
2915 3638  static int
2916 3639  smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2917 3640  {
2918 3641          smbnode_t       *np = VTOSMB(vp);
2919 3642  
2920 3643          if (!write_lock) {
2921 3644                  (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2922 3645                  return (V_WRITELOCK_FALSE);
2923 3646          }
2924 3647  
2925 3648  
2926 3649          (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2927 3650          return (V_WRITELOCK_TRUE);
2928 3651  }
2929 3652  
2930 3653  /* ARGSUSED */
2931 3654  static void
2932 3655  smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2933 3656  {
2934 3657          smbnode_t       *np = VTOSMB(vp);
2935 3658  
2936 3659          smbfs_rw_exit(&np->r_rwlock);
2937 3660  }
2938 3661  
2939 3662  
2940 3663  /* ARGSUSED */
2941 3664  static int
2942 3665  smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2943 3666  {
2944 3667          smbmntinfo_t    *smi;
2945 3668  
2946 3669          smi = VTOSMI(vp);
2947 3670  
2948 3671          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2949 3672                  return (EPERM);
2950 3673  
2951 3674          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2952 3675                  return (EIO);
2953 3676  
2954 3677          /*
2955 3678           * Because we stuff the readdir cookie into the offset field
2956 3679           * someone may attempt to do an lseek with the cookie which
2957 3680           * we want to succeed.
2958 3681           */
  
    | 
      ↓ 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);
2981 4665  
2982 4666          if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2983 4667                  return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2984 4668          else
2985 4669                  return (ENOSYS);
2986 4670  }
2987 4671  
2988 4672  /*
2989 4673   * Free storage space associated with the specified vnode.  The portion
2990 4674   * to be freed is specified by bfp->l_start and bfp->l_len (already
2991 4675   * normalized to a "whence" of 0).
2992 4676   *
2993 4677   * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2994 4678   */
2995 4679  /* ARGSUSED */
2996 4680  static int
2997 4681  smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2998 4682          offset_t offset, cred_t *cr, caller_context_t *ct)
2999 4683  {
3000 4684          int             error;
3001 4685          smbmntinfo_t    *smi;
3002 4686  
3003 4687          smi = VTOSMI(vp);
3004 4688  
3005 4689          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3006 4690                  return (EIO);
3007 4691  
3008 4692          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3009 4693                  return (EIO);
3010 4694  
3011 4695          /* Caller (fcntl) has checked v_type */
3012 4696          ASSERT(vp->v_type == VREG);
3013 4697          if (cmd != F_FREESP)
3014 4698                  return (EINVAL);
3015 4699  
3016 4700          /*
3017 4701           * Like NFS3, no 32-bit offset checks here.
3018 4702           * Our SMB layer takes care to return EFBIG
3019 4703           * when it has to fallback to a 32-bit call.
3020 4704           */
3021 4705  
3022 4706          error = convoff(vp, bfp, 0, offset);
3023 4707          if (!error) {
3024 4708                  ASSERT(bfp->l_start >= 0);
3025 4709                  if (bfp->l_len == 0) {
3026 4710                          struct vattr va;
3027 4711  
3028 4712                          /*
3029 4713                           * ftruncate should not change the ctime and
  
    | 
      ↓ 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  
3059 4754          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3060 4755                  return (EIO);
3061 4756  
3062 4757          if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3063 4758                  return (EIO);
3064 4759  
3065 4760          switch (cmd) {
3066 4761          case _PC_FILESIZEBITS:
3067 4762                  ssp = smi->smi_share;
3068 4763                  if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
3069 4764                          *valp = 64;
3070 4765                  else
3071 4766                          *valp = 32;
3072 4767                  break;
3073 4768  
3074 4769          case _PC_LINK_MAX:
3075 4770                  /* We only ever report one link to an object */
3076 4771                  *valp = 1;
3077 4772                  break;
3078 4773  
3079 4774          case _PC_ACL_ENABLED:
3080 4775                  /*
3081 4776                   * Always indicate that ACLs are enabled and
3082 4777                   * that we support ACE_T format, otherwise
3083 4778                   * libsec will ask for ACLENT_T format data
3084 4779                   * which we don't support.
3085 4780                   */
3086 4781                  *valp = _ACL_ACE_ENABLED;
3087 4782                  break;
3088 4783  
3089 4784          case _PC_SYMLINK_MAX:   /* No symlinks until we do Unix extensions */
3090 4785                  *valp = 0;
3091 4786                  break;
3092 4787  
3093 4788          case _PC_XATTR_EXISTS:
3094 4789                  if (vfs->vfs_flag & VFS_XATTR) {
3095 4790                          *valp = smbfs_xa_exists(vp, cr);
3096 4791                          break;
3097 4792                  }
3098 4793                  return (EINVAL);
3099 4794  
3100 4795          case _PC_SATTR_ENABLED:
3101 4796          case _PC_SATTR_EXISTS:
3102 4797                  *valp = 1;
3103 4798                  break;
3104 4799  
3105 4800          case _PC_TIMESTAMP_RESOLUTION:
3106 4801                  /*
3107 4802                   * Windows times are tenths of microseconds
3108 4803                   * (multiples of 100 nanoseconds).
3109 4804                   */
3110 4805                  *valp = 100L;
3111 4806                  break;
3112 4807  
3113 4808          default:
3114 4809                  return (fs_pathconf(vp, cmd, valp, cr, ct));
3115 4810          }
3116 4811          return (0);
3117 4812  }
3118 4813  
3119 4814  /* ARGSUSED */
3120 4815  static int
3121 4816  smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3122 4817          caller_context_t *ct)
3123 4818  {
3124 4819          vfs_t *vfsp;
3125 4820          smbmntinfo_t *smi;
3126 4821          int     error;
3127 4822          uint_t  mask;
3128 4823  
3129 4824          vfsp = vp->v_vfsp;
3130 4825          smi = VFTOSMI(vfsp);
3131 4826  
3132 4827          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3133 4828                  return (EIO);
3134 4829  
3135 4830          if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3136 4831                  return (EIO);
3137 4832  
3138 4833          /*
3139 4834           * Our _pathconf indicates _ACL_ACE_ENABLED,
3140 4835           * so we should only see VSA_ACE, etc here.
3141 4836           * Note: vn_create asks for VSA_DFACLCNT,
3142 4837           * and it expects ENOSYS and empty data.
3143 4838           */
3144 4839          mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3145 4840              VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3146 4841          if (mask == 0)
3147 4842                  return (ENOSYS);
3148 4843  
3149 4844          if (smi->smi_flags & SMI_ACL)
3150 4845                  error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3151 4846          else
3152 4847                  error = ENOSYS;
3153 4848  
3154 4849          if (error == ENOSYS)
3155 4850                  error = fs_fab_acl(vp, vsa, flag, cr, ct);
3156 4851  
3157 4852          return (error);
3158 4853  }
3159 4854  
3160 4855  /* ARGSUSED */
3161 4856  static int
3162 4857  smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3163 4858          caller_context_t *ct)
3164 4859  {
3165 4860          vfs_t *vfsp;
3166 4861          smbmntinfo_t *smi;
3167 4862          int     error;
3168 4863          uint_t  mask;
3169 4864  
3170 4865          vfsp = vp->v_vfsp;
3171 4866          smi = VFTOSMI(vfsp);
3172 4867  
3173 4868          if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3174 4869                  return (EIO);
3175 4870  
3176 4871          if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3177 4872                  return (EIO);
3178 4873  
3179 4874          /*
3180 4875           * Our _pathconf indicates _ACL_ACE_ENABLED,
3181 4876           * so we should only see VSA_ACE, etc here.
3182 4877           */
3183 4878          mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3184 4879          if (mask == 0)
3185 4880                  return (ENOSYS);
3186 4881  
3187 4882          if (vfsp->vfs_flag & VFS_RDONLY)
3188 4883                  return (EROFS);
3189 4884  
3190 4885          /*
3191 4886           * Allow only the mount owner to do this.
3192 4887           * See comments at smbfs_access_rwx.
3193 4888           */
3194 4889          error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3195 4890          if (error != 0)
3196 4891                  return (error);
3197 4892  
3198 4893          if (smi->smi_flags & SMI_ACL)
3199 4894                  error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3200 4895          else
3201 4896                  error = ENOSYS;
3202 4897  
3203 4898          return (error);
3204 4899  }
3205 4900  
3206 4901  
3207 4902  /*
3208 4903   * XXX
3209 4904   * This op should eventually support PSARC 2007/268.
3210 4905   */
3211 4906  static int
3212 4907  smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
  
    | 
      ↓ 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