1 /*
   2  * Copyright (c) 2000-2001 Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37  */
  38 
  39 #include <sys/systm.h>
  40 #include <sys/cred.h>
  41 #include <sys/vnode.h>
  42 #include <sys/vfs.h>
  43 #include <sys/filio.h>
  44 #include <sys/uio.h>
  45 #include <sys/dirent.h>
  46 #include <sys/errno.h>
  47 #include <sys/sunddi.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/kmem.h>
  50 #include <sys/cmn_err.h>
  51 #include <sys/vfs_opreg.h>
  52 #include <sys/policy.h>
  53 
  54 #include <netsmb/smb_osdep.h>
  55 #include <netsmb/smb.h>
  56 #include <netsmb/smb_conn.h>
  57 #include <netsmb/smb_subr.h>
  58 
  59 #include <smbfs/smbfs.h>
  60 #include <smbfs/smbfs_node.h>
  61 #include <smbfs/smbfs_subr.h>
  62 
  63 #include <sys/fs/smbfs_ioctl.h>
  64 #include <fs/fs_subr.h>
  65 
  66 /*
  67  * We assign directory offsets like the NFS client, where the
  68  * offset increments by _one_ after each directory entry.
  69  * Further, the entries "." and ".." are always at offsets
  70  * zero and one (respectively) and the "real" entries from
  71  * the server appear at offsets starting with two.  This
  72  * macro is used to initialize the n_dirofs field after
  73  * setting n_dirseq with a _findopen call.
  74  */
  75 #define FIRST_DIROFS    2
  76 
  77 /*
  78  * These characters are illegal in NTFS file names.
  79  * ref: http://support.microsoft.com/kb/147438
  80  *
  81  * Careful!  The check in the XATTR case skips the
  82  * first character to allow colon in XATTR names.
  83  */
  84 static const char illegal_chars[] = {
  85         ':',    /* colon - keep this first! */
  86         '\\',   /* back slash */
  87         '/',    /* slash */
  88         '*',    /* asterisk */
  89         '?',    /* question mark */
  90         '"',    /* double quote */
  91         '<', /* less than sign */
  92         '>', /* greater than sign */
  93         '|',    /* vertical bar */
  94         0
  95 };
  96 
  97 /*
  98  * Turning this on causes nodes to be created in the cache
  99  * during directory listings, normally avoiding a second
 100  * OtW attribute fetch just after a readdir.
 101  */
 102 int smbfs_fastlookup = 1;
 103 
 104 /* local static function defines */
 105 
 106 static int      smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
 107                         cred_t *);
 108 static int      smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
 109                         int cache_ok, caller_context_t *);
 110 static int      smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
 111                         cred_t *cr, caller_context_t *);
 112 static int      smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
 113 static int      smbfs_accessx(void *, int, cred_t *);
 114 static int      smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
 115                         caller_context_t *);
 116 static void     smbfs_rele_fid(smbnode_t *, struct smb_cred *);
 117 
 118 /*
 119  * These are the vnode ops routines which implement the vnode interface to
 120  * the networked file system.  These routines just take their parameters,
 121  * make them look networkish by putting the right info into interface structs,
 122  * and then calling the appropriate remote routine(s) to do the work.
 123  *
 124  * Note on directory name lookup cacheing:  If we detect a stale fhandle,
 125  * we purge the directory cache relative to that vnode.  This way, the
 126  * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
 127  * more details on smbnode locking.
 128  */
 129 
 130 static int      smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
 131 static int      smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
 132                         caller_context_t *);
 133 static int      smbfs_read(vnode_t *, struct uio *, int, cred_t *,
 134                         caller_context_t *);
 135 static int      smbfs_write(vnode_t *, struct uio *, int, cred_t *,
 136                         caller_context_t *);
 137 static int      smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
 138                         caller_context_t *);
 139 static int      smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
 140                         caller_context_t *);
 141 static int      smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
 142                         caller_context_t *);
 143 static int      smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
 144 static int      smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
 145 static void     smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
 146 static int      smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
 147                         int, vnode_t *, cred_t *, caller_context_t *,
 148                         int *, pathname_t *);
 149 static int      smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
 150                         int, vnode_t **, cred_t *, int, caller_context_t *,
 151                         vsecattr_t *);
 152 static int      smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
 153                         int);
 154 static int      smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
 155                         caller_context_t *, int);
 156 static int      smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
 157                         cred_t *, caller_context_t *, int, vsecattr_t *);
 158 static int      smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
 159                         caller_context_t *, int);
 160 static int      smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
 161                         caller_context_t *, int);
 162 static int      smbfs_rwlock(vnode_t *, int, caller_context_t *);
 163 static void     smbfs_rwunlock(vnode_t *, int, caller_context_t *);
 164 static int      smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
 165 static int      smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
 166                         struct flk_callback *, cred_t *, caller_context_t *);
 167 static int      smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
 168                         cred_t *, caller_context_t *);
 169 static int      smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 170                         caller_context_t *);
 171 static int      smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 172                         caller_context_t *);
 173 static int      smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 174                         caller_context_t *);
 175 static int      smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 176                         caller_context_t *);
 177 
 178 static int smbfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
 179         size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
 180         caller_context_t *ct);
 181 
 182 static int smbfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
 183         size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
 184         caller_context_t *ct);
 185 
 186 static int smbfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
 187         size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
 188         caller_context_t *ct);
 189 
 190 static int smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags,
 191         cred_t *cr, caller_context_t *ct);
 192 
 193 static int smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
 194         int flags, cred_t *cr);
 195 
 196 static int up_mapin(uio_t *uiop, page_t *pp);
 197 
 198 static int up_mapout(uio_t *uiop, page_t *pp);
 199 
 200 static int smbfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
 201         enum seg_rw rw, cred_t *cr, caller_context_t *ct);
 202 
 203 static int smbfs_getapage(vnode_t *vp, u_offset_t off, size_t len,
 204         uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw, cred_t *cr);
 205 
 206 
 207 
 208 /* Dummy function to use until correct function is ported in */
 209 int noop_vnodeop() {
 210         return (0);
 211 }
 212 
 213 struct vnodeops *smbfs_vnodeops = NULL;
 214 
 215 /*
 216  * Most unimplemented ops will return ENOSYS because of fs_nosys().
 217  * The only ops where that won't work are ACCESS (due to open(2)
 218  * failures) and ... (anything else left?)
 219  */
 220 const fs_operation_def_t smbfs_vnodeops_template[] = {
 221         { VOPNAME_OPEN,         { .vop_open = smbfs_open } },
 222         { VOPNAME_CLOSE,        { .vop_close = smbfs_close } },
 223         { VOPNAME_READ,         { .vop_read = smbfs_read } },
 224         { VOPNAME_WRITE,        { .vop_write = smbfs_write } },
 225         { VOPNAME_IOCTL,        { .vop_ioctl = smbfs_ioctl } },
 226         { VOPNAME_GETATTR,      { .vop_getattr = smbfs_getattr } },
 227         { VOPNAME_SETATTR,      { .vop_setattr = smbfs_setattr } },
 228         { VOPNAME_ACCESS,       { .vop_access = smbfs_access } },
 229         { VOPNAME_LOOKUP,       { .vop_lookup = smbfs_lookup } },
 230         { VOPNAME_CREATE,       { .vop_create = smbfs_create } },
 231         { VOPNAME_REMOVE,       { .vop_remove = smbfs_remove } },
 232         { VOPNAME_LINK,         { .error = fs_nosys } }, /* smbfs_link, */
 233         { VOPNAME_RENAME,       { .vop_rename = smbfs_rename } },
 234         { VOPNAME_MKDIR,        { .vop_mkdir = smbfs_mkdir } },
 235         { VOPNAME_RMDIR,        { .vop_rmdir = smbfs_rmdir } },
 236         { VOPNAME_READDIR,      { .vop_readdir = smbfs_readdir } },
 237         { VOPNAME_SYMLINK,      { .error = fs_nosys } }, /* smbfs_symlink, */
 238         { VOPNAME_READLINK,     { .error = fs_nosys } }, /* smbfs_readlink, */
 239         { VOPNAME_FSYNC,        { .vop_fsync = smbfs_fsync } },
 240         { VOPNAME_INACTIVE,     { .vop_inactive = smbfs_inactive } },
 241         { VOPNAME_FID,          { .error = fs_nosys } }, /* smbfs_fid, */
 242         { VOPNAME_RWLOCK,       { .vop_rwlock = smbfs_rwlock } },
 243         { VOPNAME_RWUNLOCK,     { .vop_rwunlock = smbfs_rwunlock } },
 244         { VOPNAME_SEEK,         { .vop_seek = smbfs_seek } },
 245         { VOPNAME_FRLOCK,       { .vop_frlock = smbfs_frlock } },
 246         { VOPNAME_SPACE,        { .vop_space = smbfs_space } },
 247         { VOPNAME_REALVP,       { .error = fs_nosys } }, /* smbfs_realvp, */
 248         { VOPNAME_GETPAGE,      { .vop_getpage = smbfs_getpage } }, /* smbfs_getpage, */
 249         { VOPNAME_PUTPAGE,      { .vop_putpage = smbfs_putpage } }, /* smbfs_putpage, */
 250         { VOPNAME_MAP,          { .vop_map = smbfs_map } }, /* smbfs_map, */
 251         { VOPNAME_ADDMAP,       { .vop_addmap = smbfs_addmap } }, /* smbfs_addmap, */
 252         { VOPNAME_DELMAP,       { .vop_delmap = smbfs_delmap } }, /* smbfs_delmap, */
 253         { VOPNAME_DUMP,         { .error = fs_nosys } }, /* smbfs_dump, */
 254         { VOPNAME_PATHCONF,     { .vop_pathconf = smbfs_pathconf } },
 255         { VOPNAME_PAGEIO,       { .error = fs_nosys } }, /* smbfs_pageio, */
 256         { VOPNAME_SETSECATTR,   { .vop_setsecattr = smbfs_setsecattr } },
 257         { VOPNAME_GETSECATTR,   { .vop_getsecattr = smbfs_getsecattr } },
 258         { VOPNAME_SHRLOCK,      { .vop_shrlock = smbfs_shrlock } },
 259         { NULL, NULL }
 260 };
 261 
 262 /*
 263  * XXX
 264  * When new and relevant functionality is enabled, we should be
 265  * calling vfs_set_feature() to inform callers that pieces of
 266  * functionality are available, per PSARC 2007/227.
 267  */
 268 /* ARGSUSED */
 269 static int
 270 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 271 {
 272         smbnode_t       *np;
 273         vnode_t         *vp;
 274         smbfattr_t      fa;
 275         u_int32_t       rights, rightsrcvd;
 276         u_int16_t       fid, oldfid;
 277         int             oldgenid;
 278         struct smb_cred scred;
 279         smbmntinfo_t    *smi;
 280         smb_share_t     *ssp;
 281         cred_t          *oldcr;
 282         int             tmperror;
 283         int             error = 0;
 284 
 285         vp = *vpp;
 286         np = VTOSMB(vp);
 287         smi = VTOSMI(vp);
 288         ssp = smi->smi_share;
 289 
 290         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 291                 return (EIO);
 292 
 293         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 294                 return (EIO);
 295 
 296         if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
 297                 SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
 298                 return (EACCES);
 299         }
 300 
 301         /*
 302          * Get exclusive access to n_fid and related stuff.
 303          * No returns after this until out.
 304          */
 305         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
 306                 return (EINTR);
 307         smb_credinit(&scred, cr);
 308 
 309         /*
 310          * Keep track of the vnode type at first open.
 311          * It may change later, and we need close to do
 312          * cleanup for the type we opened.  Also deny
 313          * open of new types until old type is closed.
 314          * XXX: Per-open instance nodes whould help.
 315          */
 316         if (np->n_ovtype == VNON) {
 317                 ASSERT(np->n_dirrefs == 0);
 318                 ASSERT(np->n_fidrefs == 0);
 319         } else if (np->n_ovtype != vp->v_type) {
 320                 SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
 321                     np->n_ovtype, vp->v_type);
 322                 error = EACCES;
 323                 goto out;
 324         }
 325 
 326         /*
 327          * Directory open.  See smbfs_readvdir()
 328          */
 329         if (vp->v_type == VDIR) {
 330                 if (np->n_dirseq == NULL) {
 331                         /* first open */
 332                         error = smbfs_smb_findopen(np, "*", 1,
 333                             SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
 334                             &scred, &np->n_dirseq);
 335                         if (error != 0)
 336                                 goto out;
 337                 }
 338                 np->n_dirofs = FIRST_DIROFS;
 339                 np->n_dirrefs++;
 340                 goto have_fid;
 341         }
 342 
 343         /*
 344          * If caller specified O_TRUNC/FTRUNC, then be sure to set
 345          * FWRITE (to drive successful setattr(size=0) after open)
 346          */
 347         if (flag & FTRUNC)
 348                 flag |= FWRITE;
 349 
 350         /*
 351          * If we already have it open, and the FID is still valid,
 352          * check whether the rights are sufficient for FID reuse.
 353          */
 354         if (np->n_fidrefs > 0 &&
 355             np->n_vcgenid == ssp->ss_vcgenid) {
 356                 int upgrade = 0;
 357 
 358                 if ((flag & FWRITE) &&
 359                     !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
 360                         upgrade = 1;
 361                 if ((flag & FREAD) &&
 362                     !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
 363                         upgrade = 1;
 364                 if (!upgrade) {
 365                         /*
 366                          *  the existing open is good enough
 367                          */
 368                         np->n_fidrefs++;
 369                         goto have_fid;
 370                 }
 371         }
 372         rights = np->n_fidrefs ? np->n_rights : 0;
 373 
 374         /*
 375          * we always ask for READ_CONTROL so we can always get the
 376          * owner/group IDs to satisfy a stat.  Ditto attributes.
 377          */
 378         rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
 379             SA_RIGHT_FILE_READ_ATTRIBUTES);
 380         if ((flag & FREAD))
 381                 rights |= SA_RIGHT_FILE_READ_DATA;
 382         if ((flag & FWRITE))
 383                 rights |= SA_RIGHT_FILE_WRITE_DATA |
 384                     SA_RIGHT_FILE_APPEND_DATA |
 385                     SA_RIGHT_FILE_WRITE_ATTRIBUTES;
 386 
 387         bzero(&fa, sizeof (fa));
 388         error = smbfs_smb_open(np,
 389             NULL, 0, 0, /* name nmlen xattr */
 390             rights, &scred,
 391             &fid, &rightsrcvd, &fa);
 392         if (error)
 393                 goto out;
 394         smbfs_attrcache_fa(vp, &fa);
 395 
 396         /*
 397          * We have a new FID and access rights.
 398          */
 399         oldfid = np->n_fid;
 400         oldgenid = np->n_vcgenid;
 401         np->n_fid = fid;
 402         np->n_vcgenid = ssp->ss_vcgenid;
 403         np->n_rights = rightsrcvd;
 404         np->n_fidrefs++;
 405         if (np->n_fidrefs > 1 &&
 406             oldgenid == ssp->ss_vcgenid) {
 407                 /*
 408                  * We already had it open (presumably because
 409                  * it was open with insufficient rights.)
 410                  * Close old wire-open.
 411                  */
 412                 tmperror = smbfs_smb_close(ssp,
 413                     oldfid, NULL, &scred);
 414                 if (tmperror)
 415                         SMBVDEBUG("error %d closing %s\n",
 416                             tmperror, np->n_rpath);
 417         }
 418 
 419         /*
 420          * This thread did the open.
 421          * Save our credentials too.
 422          */
 423         mutex_enter(&np->r_statelock);
 424         oldcr = np->r_cred;
 425         np->r_cred = cr;
 426         crhold(cr);
 427         if (oldcr)
 428                 crfree(oldcr);
 429         mutex_exit(&np->r_statelock);
 430 
 431 have_fid:
 432         /*
 433          * Keep track of the vnode type at first open.
 434          * (see comments above)
 435          */
 436         if (np->n_ovtype == VNON)
 437                 np->n_ovtype = vp->v_type;
 438 
 439 out:
 440         smb_credrele(&scred);
 441         smbfs_rw_exit(&np->r_lkserlock);
 442         return (error);
 443 }
 444 
 445 /*ARGSUSED*/
 446 static int
 447 smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
 448         caller_context_t *ct)
 449 {
 450         smbnode_t       *np;
 451         smbmntinfo_t    *smi;
 452         struct smb_cred scred;
 453 
 454         np = VTOSMB(vp);
 455         smi = VTOSMI(vp);
 456 
 457         /*
 458          * Don't "bail out" for VFS_UNMOUNTED here,
 459          * as we want to do cleanup, etc.
 460          */
 461 
 462         /*
 463          * zone_enter(2) prevents processes from changing zones with SMBFS files
 464          * open; if we happen to get here from the wrong zone we can't do
 465          * anything over the wire.
 466          */
 467         if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
 468                 /*
 469                  * We could attempt to clean up locks, except we're sure
 470                  * that the current process didn't acquire any locks on
 471                  * the file: any attempt to lock a file belong to another zone
 472                  * will fail, and one can't lock an SMBFS file and then change
 473                  * zones, as that fails too.
 474                  *
 475                  * Returning an error here is the sane thing to do.  A
 476                  * subsequent call to VN_RELE() which translates to a
 477                  * smbfs_inactive() will clean up state: if the zone of the
 478                  * vnode's origin is still alive and kicking, an async worker
 479                  * thread will handle the request (from the correct zone), and
 480                  * everything (minus the final smbfs_getattr_otw() call) should
 481                  * be OK. If the zone is going away smbfs_async_inactive() will
 482                  * throw away cached pages inline.
 483                  */
 484                 return (EIO);
 485         }
 486 
 487         /*
 488          * If we are using local locking for this filesystem, then
 489          * release all of the SYSV style record locks.  Otherwise,
 490          * we are doing network locking and we need to release all
 491          * of the network locks.  All of the locks held by this
 492          * process on this file are released no matter what the
 493          * incoming reference count is.
 494          */
 495         if (smi->smi_flags & SMI_LLOCK) {
 496                 pid_t pid = ddi_get_pid();
 497                 cleanlocks(vp, pid, 0);
 498                 cleanshares(vp, pid);
 499         }
 500 
 501         /*
 502          * This (passed in) count is the ref. count from the
 503          * user's file_t before the closef call (fio.c).
 504          * We only care when the reference goes away.
 505          */
 506         if (count > 1)
 507                 return (0);
 508 
 509         /*
 510          * Decrement the reference count for the FID
 511          * and possibly do the OtW close.
 512          *
 513          * Exclusive lock for modifying n_fid stuff.
 514          * Don't want this one ever interruptible.
 515          */
 516         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
 517         smb_credinit(&scred, cr);
 518 
 519         smbfs_rele_fid(np, &scred);
 520 
 521         smb_credrele(&scred);
 522         smbfs_rw_exit(&np->r_lkserlock);
 523 
 524         return (0);
 525 }
 526 
 527 /*
 528  * Helper for smbfs_close.  Decrement the reference count
 529  * for an SMB-level file or directory ID, and when the last
 530  * reference for the fid goes away, do the OtW close.
 531  * Also called in smbfs_inactive (defensive cleanup).
 532  */
 533 static void
 534 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
 535 {
 536         smb_share_t     *ssp;
 537         cred_t          *oldcr;
 538         struct smbfs_fctx *fctx;
 539         int             error;
 540         uint16_t ofid;
 541 
 542         ssp = np->n_mount->smi_share;
 543         error = 0;
 544 
 545         /* Make sure we serialize for n_dirseq use. */
 546         ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
 547 
 548         /*
 549          * Note that vp->v_type may change if a remote node
 550          * is deleted and recreated as a different type, and
 551          * our getattr may change v_type accordingly.
 552          * Now use n_ovtype to keep track of the v_type
 553          * we had during open (see comments above).
 554          */
 555         switch (np->n_ovtype) {
 556         case VDIR:
 557                 ASSERT(np->n_dirrefs > 0);
 558                 if (--np->n_dirrefs)
 559                         return;
 560                 if ((fctx = np->n_dirseq) != NULL) {
 561                         np->n_dirseq = NULL;
 562                         np->n_dirofs = 0;
 563                         error = smbfs_smb_findclose(fctx, scred);
 564                 }
 565                 break;
 566 
 567         case VREG:
 568                 ASSERT(np->n_fidrefs > 0);
 569                 if (--np->n_fidrefs)
 570                         return;
 571                 if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
 572                         np->n_fid = SMB_FID_UNUSED;
 573                         /* After reconnect, n_fid is invalid */
 574                         if (np->n_vcgenid == ssp->ss_vcgenid) {
 575                                 error = smbfs_smb_close(
 576                                     ssp, ofid, NULL, scred);
 577                         }
 578                 }
 579                 break;
 580 
 581         default:
 582                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
 583                 break;
 584         }
 585         if (error) {
 586                 SMBVDEBUG("error %d closing %s\n",
 587                     error, np->n_rpath);
 588         }
 589 
 590         /* Allow next open to use any v_type. */
 591         np->n_ovtype = VNON;
 592 
 593         /*
 594          * Other "last close" stuff.
 595          */
 596         mutex_enter(&np->r_statelock);
 597         if (np->n_flag & NATTRCHANGED)
 598                 smbfs_attrcache_rm_locked(np);
 599         oldcr = np->r_cred;
 600         np->r_cred = NULL;
 601         mutex_exit(&np->r_statelock);
 602         if (oldcr != NULL)
 603                 crfree(oldcr);
 604 }
 605 
 606 /* ARGSUSED */
 607 static int
 608 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 609         caller_context_t *ct)
 610 {
 611         struct smb_cred scred;
 612         struct vattr    va;
 613         smbnode_t       *np;
 614         smbmntinfo_t    *smi;
 615         smb_share_t     *ssp;
 616         offset_t        endoff;
 617         ssize_t         past_eof;
 618         int             error;
 619 
 620         np = VTOSMB(vp);
 621         smi = VTOSMI(vp);
 622         ssp = smi->smi_share;
 623 
 624         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 625                 return (EIO);
 626 
 627         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 628                 return (EIO);
 629 
 630         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
 631 
 632         if (vp->v_type != VREG)
 633                 return (EISDIR);
 634 
 635         if (uiop->uio_resid == 0)
 636                 return (0);
 637 
 638         /*
 639          * Like NFS3, just check for 63-bit overflow.
 640          * Our SMB layer takes care to return EFBIG
 641          * when it has to fallback to a 32-bit call.
 642          */
 643         endoff = uiop->uio_loffset + uiop->uio_resid;
 644         if (uiop->uio_loffset < 0 || endoff < 0)
 645                 return (EINVAL);
 646 
 647         /* get vnode attributes from server */
 648         va.va_mask = AT_SIZE | AT_MTIME;
 649         if (error = smbfsgetattr(vp, &va, cr))
 650                 return (error);
 651 
 652         /* Update mtime with mtime from server here? */
 653 
 654         /* if offset is beyond EOF, read nothing */
 655         if (uiop->uio_loffset >= va.va_size)
 656                 return (0);
 657 
 658         /*
 659          * Limit the read to the remaining file size.
 660          * Do this by temporarily reducing uio_resid
 661          * by the amount the lies beyoned the EOF.
 662          */
 663         if (endoff > va.va_size) {
 664                 past_eof = (ssize_t)(endoff - va.va_size);
 665                 uiop->uio_resid -= past_eof;
 666         } else
 667                 past_eof = 0;
 668 
 669         /* Shared lock for n_fid use in smb_rwuio */
 670         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 671                 return (EINTR);
 672         smb_credinit(&scred, cr);
 673 
 674         /* After reconnect, n_fid is invalid */
 675         if (np->n_vcgenid != ssp->ss_vcgenid)
 676                 error = ESTALE;
 677         else
 678                 error = smb_rwuio(ssp, np->n_fid, UIO_READ,
 679                     uiop, &scred, smb_timo_read);
 680 
 681         smb_credrele(&scred);
 682         smbfs_rw_exit(&np->r_lkserlock);
 683 
 684         /* undo adjustment of resid */
 685         uiop->uio_resid += past_eof;
 686 
 687         return (error);
 688 }
 689 
 690 
 691 /* ARGSUSED */
 692 static int
 693 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 694         caller_context_t *ct)
 695 {
 696         struct smb_cred scred;
 697         struct vattr    va;
 698         smbnode_t       *np;
 699         smbmntinfo_t    *smi;
 700         smb_share_t     *ssp;
 701         offset_t        endoff, limit;
 702         ssize_t         past_limit;
 703         int             error, timo;
 704 
 705         np = VTOSMB(vp);
 706         smi = VTOSMI(vp);
 707         ssp = smi->smi_share;
 708 
 709         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 710                 return (EIO);
 711 
 712         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 713                 return (EIO);
 714 
 715         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
 716 
 717         if (vp->v_type != VREG)
 718                 return (EISDIR);
 719 
 720         if (uiop->uio_resid == 0)
 721                 return (0);
 722 
 723         /*
 724          * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
 725          */
 726         if (ioflag & (FAPPEND | FSYNC)) {
 727                 if (np->n_flag & NMODIFIED) {
 728                         smbfs_attrcache_remove(np);
 729                         /* XXX: smbfs_vinvalbuf? */
 730                 }
 731         }
 732         if (ioflag & FAPPEND) {
 733                 /*
 734                  * File size can be changed by another client
 735                  */
 736                 va.va_mask = AT_SIZE;
 737                 if (error = smbfsgetattr(vp, &va, cr))
 738                         return (error);
 739                 uiop->uio_loffset = va.va_size;
 740         }
 741 
 742         /*
 743          * Like NFS3, just check for 63-bit overflow.
 744          */
 745         endoff = uiop->uio_loffset + uiop->uio_resid;
 746         if (uiop->uio_loffset < 0 || endoff < 0)
 747                 return (EINVAL);
 748 
 749         /*
 750          * Check to make sure that the process will not exceed
 751          * its limit on file size.  It is okay to write up to
 752          * the limit, but not beyond.  Thus, the write which
 753          * reaches the limit will be short and the next write
 754          * will return an error.
 755          *
 756          * So if we're starting at or beyond the limit, EFBIG.
 757          * Otherwise, temporarily reduce resid to the amount
 758          * the falls after the limit.
 759          */
 760         limit = uiop->uio_llimit;
 761         if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 762                 limit = MAXOFFSET_T;
 763         if (uiop->uio_loffset >= limit)
 764                 return (EFBIG);
 765         if (endoff > limit) {
 766                 past_limit = (ssize_t)(endoff - limit);
 767                 uiop->uio_resid -= past_limit;
 768         } else
 769                 past_limit = 0;
 770 
 771         /* Timeout: longer for append. */
 772         timo = smb_timo_write;
 773         if (endoff > np->r_size)
 774                 timo = smb_timo_append;
 775 
 776         /* Shared lock for n_fid use in smb_rwuio */
 777         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 778                 return (EINTR);
 779         smb_credinit(&scred, cr);
 780 
 781         /* After reconnect, n_fid is invalid */
 782         if (np->n_vcgenid != ssp->ss_vcgenid)
 783                 error = ESTALE;
 784         else
 785                 error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
 786                     uiop, &scred, timo);
 787 
 788         if (error == 0) {
 789                 mutex_enter(&np->r_statelock);
 790                 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
 791                 if (uiop->uio_loffset > (offset_t)np->r_size)
 792                         np->r_size = (len_t)uiop->uio_loffset;
 793                 mutex_exit(&np->r_statelock);
 794                 if (ioflag & (FSYNC|FDSYNC)) {
 795                         /* Don't error the I/O if this fails. */
 796                         (void) smbfs_smb_flush(np, &scred);
 797                 }
 798         }
 799 
 800         smb_credrele(&scred);
 801         smbfs_rw_exit(&np->r_lkserlock);
 802 
 803         /* undo adjustment of resid */
 804         uiop->uio_resid += past_limit;
 805 
 806         return (error);
 807 }
 808 
 809 
 810 /* ARGSUSED */
 811 static int
 812 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
 813         cred_t *cr, int *rvalp, caller_context_t *ct)
 814 {
 815         int             error;
 816         smbmntinfo_t    *smi;
 817 
 818         smi = VTOSMI(vp);
 819 
 820         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 821                 return (EIO);
 822 
 823         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 824                 return (EIO);
 825 
 826         switch (cmd) {
 827                 /* First three from ZFS. XXX - need these? */
 828 
 829         case _FIOFFS:
 830                 error = smbfs_fsync(vp, 0, cr, ct);
 831                 break;
 832 
 833                 /*
 834                  * The following two ioctls are used by bfu.
 835                  * Silently ignore to avoid bfu errors.
 836                  */
 837         case _FIOGDIO:
 838         case _FIOSDIO:
 839                 error = 0;
 840                 break;
 841 
 842 #ifdef NOT_YET  /* XXX - from the NFS code. */
 843         case _FIODIRECTIO:
 844                 error = smbfs_directio(vp, (int)arg, cr);
 845 #endif
 846 
 847                 /*
 848                  * Allow get/set with "raw" security descriptor (SD) data.
 849                  * Useful for testing, diagnosing idmap problems, etc.
 850                  */
 851         case SMBFSIO_GETSD:
 852                 error = smbfs_acl_iocget(vp, arg, flag, cr);
 853                 break;
 854 
 855         case SMBFSIO_SETSD:
 856                 error = smbfs_acl_iocset(vp, arg, flag, cr);
 857                 break;
 858 
 859         default:
 860                 error = ENOTTY;
 861                 break;
 862         }
 863 
 864         return (error);
 865 }
 866 
 867 
 868 /*
 869  * Return either cached or remote attributes. If get remote attr
 870  * use them to check and invalidate caches, then cache the new attributes.
 871  *
 872  * XXX
 873  * This op should eventually support PSARC 2007/315, Extensible Attribute
 874  * Interfaces, for richer metadata.
 875  */
 876 /* ARGSUSED */
 877 static int
 878 smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 879         caller_context_t *ct)
 880 {
 881         smbnode_t *np;
 882         smbmntinfo_t *smi;
 883 
 884         smi = VTOSMI(vp);
 885 
 886         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 887                 return (EIO);
 888 
 889         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 890                 return (EIO);
 891 
 892         /*
 893          * If it has been specified that the return value will
 894          * just be used as a hint, and we are only being asked
 895          * for size, fsid or rdevid, then return the client's
 896          * notion of these values without checking to make sure
 897          * that the attribute cache is up to date.
 898          * The whole point is to avoid an over the wire GETATTR
 899          * call.
 900          */
 901         np = VTOSMB(vp);
 902         if (flags & ATTR_HINT) {
 903                 if (vap->va_mask ==
 904                     (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
 905                         mutex_enter(&np->r_statelock);
 906                         if (vap->va_mask | AT_SIZE)
 907                                 vap->va_size = np->r_size;
 908                         if (vap->va_mask | AT_FSID)
 909                                 vap->va_fsid = vp->v_vfsp->vfs_dev;
 910                         if (vap->va_mask | AT_RDEV)
 911                                 vap->va_rdev = vp->v_rdev;
 912                         mutex_exit(&np->r_statelock);
 913                         return (0);
 914                 }
 915         }
 916 
 917         return (smbfsgetattr(vp, vap, cr));
 918 }
 919 
 920 /* smbfsgetattr() in smbfs_client.c */
 921 
 922 /*
 923  * XXX
 924  * This op should eventually support PSARC 2007/315, Extensible Attribute
 925  * Interfaces, for richer metadata.
 926  */
 927 /*ARGSUSED4*/
 928 static int
 929 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 930                 caller_context_t *ct)
 931 {
 932         vfs_t           *vfsp;
 933         smbmntinfo_t    *smi;
 934         int             error;
 935         uint_t          mask;
 936         struct vattr    oldva;
 937 
 938         vfsp = vp->v_vfsp;
 939         smi = VFTOSMI(vfsp);
 940 
 941         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 942                 return (EIO);
 943 
 944         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
 945                 return (EIO);
 946 
 947         mask = vap->va_mask;
 948         if (mask & AT_NOSET)
 949                 return (EINVAL);
 950 
 951         if (vfsp->vfs_flag & VFS_RDONLY)
 952                 return (EROFS);
 953 
 954         /*
 955          * This is a _local_ access check so that only the owner of
 956          * this mount can set attributes.  With ACLs enabled, the
 957          * file owner can be different from the mount owner, and we
 958          * need to check the _mount_ owner here.  See _access_rwx
 959          */
 960         bzero(&oldva, sizeof (oldva));
 961         oldva.va_mask = AT_TYPE | AT_MODE;
 962         error = smbfsgetattr(vp, &oldva, cr);
 963         if (error)
 964                 return (error);
 965         oldva.va_mask |= AT_UID | AT_GID;
 966         oldva.va_uid = smi->smi_uid;
 967         oldva.va_gid = smi->smi_gid;
 968 
 969         error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
 970             smbfs_accessx, vp);
 971         if (error)
 972                 return (error);
 973 
 974         if (mask & (AT_UID | AT_GID)) {
 975                 if (smi->smi_flags & SMI_ACL)
 976                         error = smbfs_acl_setids(vp, vap, cr);
 977                 else
 978                         error = ENOSYS;
 979                 if (error != 0) {
 980                         SMBVDEBUG("error %d seting UID/GID on %s",
 981                             error, VTOSMB(vp)->n_rpath);
 982                         /*
 983                          * It might be more correct to return the
 984                          * error here, but that causes complaints
 985                          * when root extracts a cpio archive, etc.
 986                          * So ignore this error, and go ahead with
 987                          * the rest of the setattr work.
 988                          */
 989                 }
 990         }
 991 
 992         return (smbfssetattr(vp, vap, flags, cr));
 993 }
 994 
 995 /*
 996  * Mostly from Darwin smbfs_setattr()
 997  * but then modified a lot.
 998  */
 999 /* ARGSUSED */
1000 static int
1001 smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
1002 {
1003         int             error = 0;
1004         smbnode_t       *np = VTOSMB(vp);
1005         uint_t          mask = vap->va_mask;
1006         struct timespec *mtime, *atime;
1007         struct smb_cred scred;
1008         int             cerror, modified = 0;
1009         unsigned short  fid;
1010         int have_fid = 0;
1011         uint32_t rights = 0;
1012 
1013         ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
1014 
1015         /*
1016          * There are no settable attributes on the XATTR dir,
1017          * so just silently ignore these.  On XATTR files,
1018          * you can set the size but nothing else.
1019          */
1020         if (vp->v_flag & V_XATTRDIR)
1021                 return (0);
1022         if (np->n_flag & N_XATTR) {
1023                 if (mask & AT_TIMES)
1024                         SMBVDEBUG("ignore set time on xattr\n");
1025                 mask &= AT_SIZE;
1026         }
1027 
1028         /*
1029          * If our caller is trying to set multiple attributes, they
1030          * can make no assumption about what order they are done in.
1031          * Here we try to do them in order of decreasing likelihood
1032          * of failure, just to minimize the chance we'll wind up
1033          * with a partially complete request.
1034          */
1035 
1036         /* Shared lock for (possible) n_fid use. */
1037         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1038                 return (EINTR);
1039         smb_credinit(&scred, cr);
1040 
1041         /*
1042          * Will we need an open handle for this setattr?
1043          * If so, what rights will we need?
1044          */
1045         if (mask & (AT_ATIME | AT_MTIME)) {
1046                 rights |=
1047                     SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1048         }
1049         if (mask & AT_SIZE) {
1050                 rights |=
1051                     SA_RIGHT_FILE_WRITE_DATA |
1052                     SA_RIGHT_FILE_APPEND_DATA;
1053         }
1054 
1055         /*
1056          * Only SIZE really requires a handle, but it's
1057          * simpler and more reliable to set via a handle.
1058          * Some servers like NT4 won't set times by path.
1059          * Also, we're usually setting everything anyway.
1060          */
1061         if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) {
1062                 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1063                 if (error) {
1064                         SMBVDEBUG("error %d opening %s\n",
1065                             error, np->n_rpath);
1066                         goto out;
1067                 }
1068                 have_fid = 1;
1069         }
1070 
1071         /*
1072          * If the server supports the UNIX extensions, right here is where
1073          * we'd support changes to uid, gid, mode, and possibly va_flags.
1074          * For now we claim to have made any such changes.
1075          */
1076 
1077         if (mask & AT_SIZE) {
1078                 /*
1079                  * If the new file size is less than what the client sees as
1080                  * the file size, then just change the size and invalidate
1081                  * the pages.
1082                  * I am commenting this code at present because the function
1083                  * smbfs_putapage() is not yet implemented.
1084                  */
1085 
1086                 /*
1087                  * Set the file size to vap->va_size.
1088                  */
1089                 ASSERT(have_fid);
1090                 error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1091                 if (error) {
1092                         SMBVDEBUG("setsize error %d file %s\n",
1093                             error, np->n_rpath);
1094                 } else {
1095                         /*
1096                          * Darwin had code here to zero-extend.
1097                          * Tests indicate the server will zero-fill,
1098                          * so looks like we don't need to do this.
1099                          * Good thing, as this could take forever.
1100                          *
1101                          * XXX: Reportedly, writing one byte of zero
1102                          * at the end offset avoids problems here.
1103                          */
1104                         mutex_enter(&np->r_statelock);
1105                         np->r_size = vap->va_size;
1106                         mutex_exit(&np->r_statelock);
1107                         modified = 1;
1108                 }
1109         }
1110 
1111         /*
1112          * XXX: When Solaris has create_time, set that too.
1113          * Note: create_time is different from ctime.
1114          */
1115         mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1116         atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1117 
1118         if (mtime || atime) {
1119                 /*
1120                  * Always use the handle-based set attr call now.
1121                  * Not trying to set DOS attributes here so pass zero.
1122                  */
1123                 ASSERT(have_fid);
1124                 error = smbfs_smb_setfattr(np, fid,
1125                     0, mtime, atime, &scred);
1126                 if (error) {
1127                         SMBVDEBUG("set times error %d file %s\n",
1128                             error, np->n_rpath);
1129                 } else {
1130                         modified = 1;
1131                 }
1132         }
1133 
1134 out:
1135         if (modified) {
1136                 /*
1137                  * Invalidate attribute cache in case the server
1138                  * doesn't set exactly the attributes we asked.
1139                  */
1140                 smbfs_attrcache_remove(np);
1141         }
1142 
1143         if (have_fid) {
1144                 cerror = smbfs_smb_tmpclose(np, fid, &scred);
1145                 if (cerror)
1146                         SMBVDEBUG("error %d closing %s\n",
1147                             cerror, np->n_rpath);
1148         }
1149 
1150         smb_credrele(&scred);
1151         smbfs_rw_exit(&np->r_lkserlock);
1152 
1153         return (error);
1154 }
1155 
1156 /*
1157  * smbfs_access_rwx()
1158  * Common function for smbfs_access, etc.
1159  *
1160  * The security model implemented by the FS is unusual
1161  * due to the current "single user mounts" restriction:
1162  * All access under a given mount point uses the CIFS
1163  * credentials established by the owner of the mount.
1164  *
1165  * Most access checking is handled by the CIFS server,
1166  * but we need sufficient Unix access checks here to
1167  * prevent other local Unix users from having access
1168  * to objects under this mount that the uid/gid/mode
1169  * settings in the mount would not allow.
1170  *
1171  * With this model, there is a case where we need the
1172  * ability to do an access check before we have the
1173  * vnode for an object.  This function takes advantage
1174  * of the fact that the uid/gid/mode is per mount, and
1175  * avoids the need for a vnode.
1176  *
1177  * We still (sort of) need a vnode when we call
1178  * secpolicy_vnode_access, but that only uses
1179  * the vtype field, so we can use a pair of fake
1180  * vnodes that have only v_type filled in.
1181  *
1182  * XXX: Later, add a new secpolicy_vtype_access()
1183  * that takes the vtype instead of a vnode, and
1184  * get rid of the tmpl_vxxx fake vnodes below.
1185  */
1186 static int
1187 smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1188 {
1189         /* See the secpolicy call below. */
1190         static const vnode_t tmpl_vdir = { .v_type = VDIR };
1191         static const vnode_t tmpl_vreg = { .v_type = VREG };
1192         vattr_t         va;
1193         vnode_t         *tvp;
1194         struct smbmntinfo *smi = VFTOSMI(vfsp);
1195         int shift = 0;
1196 
1197         /*
1198          * Build our (fabricated) vnode attributes.
1199          * XXX: Could make these templates in the
1200          * per-mount struct and use them here.
1201          */
1202         bzero(&va, sizeof (va));
1203         va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1204         va.va_type = vtype;
1205         va.va_mode = (vtype == VDIR) ?
1206             smi->smi_dmode : smi->smi_fmode;
1207         va.va_uid = smi->smi_uid;
1208         va.va_gid = smi->smi_gid;
1209 
1210         /*
1211          * Disallow write attempts on read-only file systems,
1212          * unless the file is a device or fifo node.  Note:
1213          * Inline vn_is_readonly and IS_DEVVP here because
1214          * we may not have a vnode ptr.  Original expr. was:
1215          * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1216          */
1217         if ((mode & VWRITE) &&
1218             (vfsp->vfs_flag & VFS_RDONLY) &&
1219             !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1220                 return (EROFS);
1221 
1222         /*
1223          * Disallow attempts to access mandatory lock files.
1224          * Similarly, expand MANDLOCK here.
1225          * XXX: not sure we need this.
1226          */
1227         if ((mode & (VWRITE | VREAD | VEXEC)) &&
1228             va.va_type == VREG && MANDMODE(va.va_mode))
1229                 return (EACCES);
1230 
1231         /*
1232          * Access check is based on only
1233          * one of owner, group, public.
1234          * If not owner, then check group.
1235          * If not a member of the group,
1236          * then check public access.
1237          */
1238         if (crgetuid(cr) != va.va_uid) {
1239                 shift += 3;
1240                 if (!groupmember(va.va_gid, cr))
1241                         shift += 3;
1242         }
1243 
1244         /*
1245          * We need a vnode for secpolicy_vnode_access,
1246          * but the only thing it looks at is v_type,
1247          * so pass one of the templates above.
1248          */
1249         tvp = (va.va_type == VDIR) ?
1250             (vnode_t *)&tmpl_vdir :
1251             (vnode_t *)&tmpl_vreg;
1252 
1253         return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1254             va.va_mode << shift, mode));
1255 }
1256 
1257 /*
1258  * See smbfs_setattr
1259  */
1260 static int
1261 smbfs_accessx(void *arg, int mode, cred_t *cr)
1262 {
1263         vnode_t *vp = arg;
1264         /*
1265          * Note: The caller has checked the current zone,
1266          * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1267          */
1268         return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1269 }
1270 
1271 /*
1272  * XXX
1273  * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1274  */
1275 /* ARGSUSED */
1276 static int
1277 smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1278 {
1279         vfs_t           *vfsp;
1280         smbmntinfo_t    *smi;
1281 
1282         vfsp = vp->v_vfsp;
1283         smi = VFTOSMI(vfsp);
1284 
1285         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1286                 return (EIO);
1287 
1288         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1289                 return (EIO);
1290 
1291         return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1292 }
1293 
1294 
1295 /*
1296  * Flush local dirty pages to stable storage on the server.
1297  *
1298  * If FNODSYNC is specified, then there is nothing to do because
1299  * metadata changes are not cached on the client before being
1300  * sent to the server.
1301  */
1302 /* ARGSUSED */
1303 static int
1304 smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1305 {
1306         int             error = 0;
1307         smbmntinfo_t    *smi;
1308         smbnode_t       *np;
1309         struct smb_cred scred;
1310 
1311         np = VTOSMB(vp);
1312         smi = VTOSMI(vp);
1313 
1314         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1315                 return (EIO);
1316 
1317         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1318                 return (EIO);
1319 
1320         if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1321                 return (0);
1322 
1323         if ((syncflag & (FSYNC|FDSYNC)) == 0)
1324                 return (0);
1325 
1326         /* Shared lock for n_fid use in _flush */
1327         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1328                 return (EINTR);
1329         smb_credinit(&scred, cr);
1330 
1331         error = smbfs_smb_flush(np, &scred);
1332 
1333         smb_credrele(&scred);
1334         smbfs_rw_exit(&np->r_lkserlock);
1335 
1336         return (error);
1337 }
1338 
1339 /*
1340  * Last reference to vnode went away.
1341  */
1342 /* ARGSUSED */
1343 static void
1344 smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1345 {
1346         smbnode_t       *np;
1347         struct smb_cred scred;
1348 
1349         /*
1350          * Don't "bail out" for VFS_UNMOUNTED here,
1351          * as we want to do cleanup, etc.
1352          * See also pcfs_inactive
1353          */
1354 
1355         np = VTOSMB(vp);
1356 
1357         /*
1358          * If this is coming from the wrong zone, we let someone in the right
1359          * zone take care of it asynchronously.  We can get here due to
1360          * VN_RELE() being called from pageout() or fsflush().  This call may
1361          * potentially turn into an expensive no-op if, for instance, v_count
1362          * gets incremented in the meantime, but it's still correct.
1363          */
1364 
1365         /*
1366          * Defend against the possibility that higher-level callers
1367          * might not correctly balance open and close calls.  If we
1368          * get here with open references remaining, it means there
1369          * was a missing VOP_CLOSE somewhere.  If that happens, do
1370          * the close here so we don't "leak" FIDs on the server.
1371          *
1372          * Exclusive lock for modifying n_fid stuff.
1373          * Don't want this one ever interruptible.
1374          */
1375         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
1376         smb_credinit(&scred, cr);
1377 
1378         switch (np->n_ovtype) {
1379         case VNON:
1380                 /* not open (OK) */
1381                 break;
1382 
1383         case VDIR:
1384                 if (np->n_dirrefs == 0)
1385                         break;
1386                 SMBVDEBUG("open dir: refs %d path %s\n",
1387                     np->n_dirrefs, np->n_rpath);
1388                 /* Force last close. */
1389                 np->n_dirrefs = 1;
1390                 smbfs_rele_fid(np, &scred);
1391                 break;
1392 
1393         case VREG:
1394                 if (np->n_fidrefs == 0)
1395                         break;
1396                 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1397                     np->n_fidrefs, np->n_fid, np->n_rpath);
1398                 /* Force last close. */
1399                 np->n_fidrefs = 1;
1400                 smbfs_rele_fid(np, &scred);
1401                 break;
1402 
1403         default:
1404                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1405                 np->n_ovtype = VNON;
1406                 break;
1407         }
1408 
1409         smb_credrele(&scred);
1410         smbfs_rw_exit(&np->r_lkserlock);
1411 
1412         smbfs_addfree(np);
1413 }
1414 
1415 /*
1416  * Remote file system operations having to do with directory manipulation.
1417  */
1418 /* ARGSUSED */
1419 static int
1420 smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1421         int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1422         int *direntflags, pathname_t *realpnp)
1423 {
1424         vfs_t           *vfs;
1425         smbmntinfo_t    *smi;
1426         smbnode_t       *dnp;
1427         int             error;
1428 
1429         vfs = dvp->v_vfsp;
1430         smi = VFTOSMI(vfs);
1431 
1432         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1433                 return (EPERM);
1434 
1435         if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1436                 return (EIO);
1437 
1438         dnp = VTOSMB(dvp);
1439 
1440         /*
1441          * Are we looking up extended attributes?  If so, "dvp" is
1442          * the file or directory for which we want attributes, and
1443          * we need a lookup of the (faked up) attribute directory
1444          * before we lookup the rest of the path.
1445          */
1446         if (flags & LOOKUP_XATTR) {
1447                 /*
1448                  * Require the xattr mount option.
1449                  */
1450                 if ((vfs->vfs_flag & VFS_XATTR) == 0)
1451                         return (EINVAL);
1452 
1453                 error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1454                 return (error);
1455         }
1456 
1457         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1458                 return (EINTR);
1459 
1460         error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1461 
1462         smbfs_rw_exit(&dnp->r_rwlock);
1463 
1464         return (error);
1465 }
1466 
1467 /* ARGSUSED */
1468 static int
1469 smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1470         int cache_ok, caller_context_t *ct)
1471 {
1472         int             error;
1473         int             supplen; /* supported length */
1474         vnode_t         *vp;
1475         smbnode_t       *np;
1476         smbnode_t       *dnp;
1477         smbmntinfo_t    *smi;
1478         /* struct smb_vc        *vcp; */
1479         const char      *ill;
1480         const char      *name = (const char *)nm;
1481         int             nmlen = strlen(nm);
1482         int             rplen;
1483         struct smb_cred scred;
1484         struct smbfattr fa;
1485 
1486         smi = VTOSMI(dvp);
1487         dnp = VTOSMB(dvp);
1488 
1489         ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1490 
1491 #ifdef NOT_YET
1492         vcp = SSTOVC(smi->smi_share);
1493 
1494         /* XXX: Should compute this once and store it in smbmntinfo_t */
1495         supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1496 #else
1497         supplen = 255;
1498 #endif
1499 
1500         /*
1501          * RWlock must be held, either reader or writer.
1502          * XXX: Can we check without looking directly
1503          * inside the struct smbfs_rwlock_t?
1504          */
1505         ASSERT(dnp->r_rwlock.count != 0);
1506 
1507         /*
1508          * If lookup is for "", just return dvp.
1509          * No need to perform any access checks.
1510          */
1511         if (nmlen == 0) {
1512                 VN_HOLD(dvp);
1513                 *vpp = dvp;
1514                 return (0);
1515         }
1516 
1517         /*
1518          * Can't do lookups in non-directories.
1519          */
1520         if (dvp->v_type != VDIR)
1521                 return (ENOTDIR);
1522 
1523         /*
1524          * Need search permission in the directory.
1525          */
1526         error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1527         if (error)
1528                 return (error);
1529 
1530         /*
1531          * If lookup is for ".", just return dvp.
1532          * Access check was done above.
1533          */
1534         if (nmlen == 1 && name[0] == '.') {
1535                 VN_HOLD(dvp);
1536                 *vpp = dvp;
1537                 return (0);
1538         }
1539 
1540         /*
1541          * Now some sanity checks on the name.
1542          * First check the length.
1543          */
1544         if (nmlen > supplen)
1545                 return (ENAMETOOLONG);
1546 
1547         /*
1548          * Avoid surprises with characters that are
1549          * illegal in Windows file names.
1550          * Todo: CATIA mappings  XXX
1551          */
1552         ill = illegal_chars;
1553         if (dnp->n_flag & N_XATTR)
1554                 ill++; /* allow colon */
1555         if (strpbrk(nm, ill))
1556                 return (EINVAL);
1557 
1558         /*
1559          * Special handling for lookup of ".."
1560          *
1561          * We keep full pathnames (as seen on the server)
1562          * so we can just trim off the last component to
1563          * get the full pathname of the parent.  Note:
1564          * We don't actually copy and modify, but just
1565          * compute the trimmed length and pass that with
1566          * the current dir path (not null terminated).
1567          *
1568          * We don't go over-the-wire to get attributes
1569          * for ".." because we know it's a directory,
1570          * and we can just leave the rest "stale"
1571          * until someone does a getattr.
1572          */
1573         if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1574                 if (dvp->v_flag & VROOT) {
1575                         /*
1576                          * Already at the root.  This can happen
1577                          * with directory listings at the root,
1578                          * which lookup "." and ".." to get the
1579                          * inode numbers.  Let ".." be the same
1580                          * as "." in the FS root.
1581                          */
1582                         VN_HOLD(dvp);
1583                         *vpp = dvp;
1584                         return (0);
1585                 }
1586 
1587                 /*
1588                  * Special case for XATTR directory
1589                  */
1590                 if (dvp->v_flag & V_XATTRDIR) {
1591                         error = smbfs_xa_parent(dvp, vpp);
1592                         return (error);
1593                 }
1594 
1595                 /*
1596                  * Find the parent path length.
1597                  */
1598                 rplen = dnp->n_rplen;
1599                 ASSERT(rplen > 0);
1600                 while (--rplen >= 0) {
1601                         if (dnp->n_rpath[rplen] == '\\')
1602                                 break;
1603                 }
1604                 if (rplen <= 0) {
1605                         /* Found our way to the root. */
1606                         vp = SMBTOV(smi->smi_root);
1607                         VN_HOLD(vp);
1608                         *vpp = vp;
1609                         return (0);
1610                 }
1611                 np = smbfs_node_findcreate(smi,
1612                     dnp->n_rpath, rplen, NULL, 0, 0,
1613                     &smbfs_fattr0); /* force create */
1614                 ASSERT(np != NULL);
1615                 vp = SMBTOV(np);
1616                 vp->v_type = VDIR;
1617 
1618                 /* Success! */
1619                 *vpp = vp;
1620                 return (0);
1621         }
1622 
1623         /*
1624          * Normal lookup of a name under this directory.
1625          * Note we handled "", ".", ".." above.
1626          */
1627         if (cache_ok) {
1628                 /*
1629                  * The caller indicated that it's OK to use a
1630                  * cached result for this lookup, so try to
1631                  * reclaim a node from the smbfs node cache.
1632                  */
1633                 error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1634                 if (error)
1635                         return (error);
1636                 if (vp != NULL) {
1637                         /* hold taken in lookup_cache */
1638                         *vpp = vp;
1639                         return (0);
1640                 }
1641         }
1642 
1643         /*
1644          * OK, go over-the-wire to get the attributes,
1645          * then create the node.
1646          */
1647         smb_credinit(&scred, cr);
1648         /* Note: this can allocate a new "name" */
1649         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1650         smb_credrele(&scred);
1651         if (error == ENOTDIR) {
1652                 /*
1653                  * Lookup failed because this directory was
1654                  * removed or renamed by another client.
1655                  * Remove any cached attributes under it.
1656                  */
1657                 smbfs_attrcache_remove(dnp);
1658                 smbfs_attrcache_prune(dnp);
1659         }
1660         if (error)
1661                 goto out;
1662 
1663         error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1664         if (error)
1665                 goto out;
1666 
1667         /* Success! */
1668         *vpp = vp;
1669 
1670 out:
1671         /* smbfs_smb_lookup may have allocated name. */
1672         if (name != nm)
1673                 smbfs_name_free(name, nmlen);
1674 
1675         return (error);
1676 }
1677 
1678 /*
1679  * smbfslookup_cache
1680  *
1681  * Try to reclaim a node from the smbfs node cache.
1682  * Some statistics for DEBUG.
1683  *
1684  * This mechanism lets us avoid many of the five (or more)
1685  * OtW lookup calls per file seen with "ls -l" if we search
1686  * the smbfs node cache for recently inactive(ated) nodes.
1687  */
1688 #ifdef DEBUG
1689 int smbfs_lookup_cache_calls = 0;
1690 int smbfs_lookup_cache_error = 0;
1691 int smbfs_lookup_cache_miss = 0;
1692 int smbfs_lookup_cache_stale = 0;
1693 int smbfs_lookup_cache_hits = 0;
1694 #endif /* DEBUG */
1695 
1696 /* ARGSUSED */
1697 static int
1698 smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1699         vnode_t **vpp, cred_t *cr)
1700 {
1701         struct vattr va;
1702         smbnode_t *dnp;
1703         smbnode_t *np;
1704         vnode_t *vp;
1705         int error;
1706         char sep;
1707 
1708         dnp = VTOSMB(dvp);
1709         *vpp = NULL;
1710 
1711 #ifdef DEBUG
1712         smbfs_lookup_cache_calls++;
1713 #endif
1714 
1715         /*
1716          * First make sure we can get attributes for the
1717          * directory.  Cached attributes are OK here.
1718          * If we removed or renamed the directory, this
1719          * will return ENOENT.  If someone else removed
1720          * this directory or file, we'll find out when we
1721          * try to open or get attributes.
1722          */
1723         va.va_mask = AT_TYPE | AT_MODE;
1724         error = smbfsgetattr(dvp, &va, cr);
1725         if (error) {
1726 #ifdef DEBUG
1727                 smbfs_lookup_cache_error++;
1728 #endif
1729                 return (error);
1730         }
1731 
1732         /*
1733          * Passing NULL smbfattr here so we will
1734          * just look, not create.
1735          */
1736         sep = SMBFS_DNP_SEP(dnp);
1737         np = smbfs_node_findcreate(dnp->n_mount,
1738             dnp->n_rpath, dnp->n_rplen,
1739             nm, nmlen, sep, NULL);
1740         if (np == NULL) {
1741 #ifdef DEBUG
1742                 smbfs_lookup_cache_miss++;
1743 #endif
1744                 return (0);
1745         }
1746 
1747         /*
1748          * Found it.  Attributes still valid?
1749          */
1750         vp = SMBTOV(np);
1751         if (np->r_attrtime <= gethrtime()) {
1752                 /* stale */
1753 #ifdef DEBUG
1754                 smbfs_lookup_cache_stale++;
1755 #endif
1756                 VN_RELE(vp);
1757                 return (0);
1758         }
1759 
1760         /*
1761          * Success!
1762          * Caller gets hold from smbfs_node_findcreate
1763          */
1764 #ifdef DEBUG
1765         smbfs_lookup_cache_hits++;
1766 #endif
1767         *vpp = vp;
1768         return (0);
1769 }
1770 
1771 /*
1772  * XXX
1773  * vsecattr_t is new to build 77, and we need to eventually support
1774  * it in order to create an ACL when an object is created.
1775  *
1776  * This op should support the new FIGNORECASE flag for case-insensitive
1777  * lookups, per PSARC 2007/244.
1778  */
1779 /* ARGSUSED */
1780 static int
1781 smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1782         int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1783         vsecattr_t *vsecp)
1784 {
1785         int             error;
1786         int             cerror;
1787         vfs_t           *vfsp;
1788         vnode_t         *vp;
1789 #ifdef NOT_YET
1790         smbnode_t       *np;
1791 #endif
1792         smbnode_t       *dnp;
1793         smbmntinfo_t    *smi;
1794         struct vattr    vattr;
1795         struct smbfattr fattr;
1796         struct smb_cred scred;
1797         const char *name = (const char *)nm;
1798         int             nmlen = strlen(nm);
1799         uint32_t        disp;
1800         uint16_t        fid;
1801         int             xattr;
1802 
1803         vfsp = dvp->v_vfsp;
1804         smi = VFTOSMI(vfsp);
1805         dnp = VTOSMB(dvp);
1806         vp = NULL;
1807 
1808         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1809                 return (EPERM);
1810 
1811         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1812                 return (EIO);
1813 
1814         /*
1815          * Note: this may break mknod(2) calls to create a directory,
1816          * but that's obscure use.  Some other filesystems do this.
1817          * XXX: Later, redirect VDIR type here to _mkdir.
1818          */
1819         if (va->va_type != VREG)
1820                 return (EINVAL);
1821 
1822         /*
1823          * If the pathname is "", just use dvp, no checks.
1824          * Do this outside of the rwlock (like zfs).
1825          */
1826         if (nmlen == 0) {
1827                 VN_HOLD(dvp);
1828                 *vpp = dvp;
1829                 return (0);
1830         }
1831 
1832         /* Don't allow "." or ".." through here. */
1833         if ((nmlen == 1 && name[0] == '.') ||
1834             (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1835                 return (EISDIR);
1836 
1837         /*
1838          * We make a copy of the attributes because the caller does not
1839          * expect us to change what va points to.
1840          */
1841         vattr = *va;
1842 
1843         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1844                 return (EINTR);
1845         smb_credinit(&scred, cr);
1846 
1847         /*
1848          * XXX: Do we need r_lkserlock too?
1849          * No use of any shared fid or fctx...
1850          */
1851 
1852         /*
1853          * NFS needs to go over the wire, just to be sure whether the
1854          * file exists or not.  Using a cached result is dangerous in
1855          * this case when making a decision regarding existence.
1856          *
1857          * The SMB protocol does NOT really need to go OTW here
1858          * thanks to the expressive NTCREATE disposition values.
1859          * Unfortunately, to do Unix access checks correctly,
1860          * we need to know if the object already exists.
1861          * When the object does not exist, we need VWRITE on
1862          * the directory.  Note: smbfslookup() checks VEXEC.
1863          */
1864         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1865         if (error == 0) {
1866                 /*
1867                  * The file already exists.  Error?
1868                  * NB: have a hold from smbfslookup
1869                  */
1870                 if (exclusive == EXCL) {
1871                         error = EEXIST;
1872                         VN_RELE(vp);
1873                         goto out;
1874                 }
1875                 /*
1876                  * Verify requested access.
1877                  */
1878                 error = smbfs_access(vp, mode, 0, cr, ct);
1879                 if (error) {
1880                         VN_RELE(vp);
1881                         goto out;
1882                 }
1883 
1884                 /*
1885                  * Truncate (if requested).
1886                  */
1887                 if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1888                         vattr.va_mask = AT_SIZE;
1889                         error = smbfssetattr(vp, &vattr, 0, cr);
1890                         if (error) {
1891                                 VN_RELE(vp);
1892                                 goto out;
1893                         }
1894                 }
1895                 /* Success! */
1896 #ifdef NOT_YET
1897                 vnevent_create(vp, ct);
1898 #endif
1899                 *vpp = vp;
1900                 goto out;
1901         }
1902 
1903         /*
1904          * The file did not exist.  Need VWRITE in the directory.
1905          */
1906         error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1907         if (error)
1908                 goto out;
1909 
1910         /*
1911          * Now things get tricky.  We also need to check the
1912          * requested open mode against the file we may create.
1913          * See comments at smbfs_access_rwx
1914          */
1915         error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1916         if (error)
1917                 goto out;
1918 
1919         /*
1920          * Now the code derived from Darwin,
1921          * but with greater use of NT_CREATE
1922          * disposition options.  Much changed.
1923          *
1924          * Create (or open) a new child node.
1925          * Note we handled "." and ".." above.
1926          */
1927 
1928         if (exclusive == EXCL)
1929                 disp = NTCREATEX_DISP_CREATE;
1930         else {
1931                 /* Truncate regular files if requested. */
1932                 if ((va->va_type == VREG) &&
1933                     (va->va_mask & AT_SIZE) &&
1934                     (va->va_size == 0))
1935                         disp = NTCREATEX_DISP_OVERWRITE_IF;
1936                 else
1937                         disp = NTCREATEX_DISP_OPEN_IF;
1938         }
1939         xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1940         error = smbfs_smb_create(dnp,
1941             name, nmlen, xattr,
1942             disp, &scred, &fid);
1943         if (error)
1944                 goto out;
1945 
1946         /*
1947          * XXX: Missing some code here to deal with
1948          * the case where we opened an existing file,
1949          * it's size is larger than 32-bits, and we're
1950          * setting the size from a process that's not
1951          * aware of large file offsets.  i.e.
1952          * from the NFS3 code:
1953          */
1954 #if NOT_YET /* XXX */
1955         if ((vattr.va_mask & AT_SIZE) &&
1956             vp->v_type == VREG) {
1957                 np = VTOSMB(vp);
1958                 /*
1959                  * Check here for large file handled
1960                  * by LF-unaware process (as
1961                  * ufs_create() does)
1962                  */
1963                 if (!(lfaware & FOFFMAX)) {
1964                         mutex_enter(&np->r_statelock);
1965                         if (np->r_size > MAXOFF32_T)
1966                                 error = EOVERFLOW;
1967                         mutex_exit(&np->r_statelock);
1968                 }
1969                 if (!error) {
1970                         vattr.va_mask = AT_SIZE;
1971                         error = smbfssetattr(vp,
1972                             &vattr, 0, cr);
1973                 }
1974         }
1975 #endif /* XXX */
1976         /*
1977          * Should use the fid to get/set the size
1978          * while we have it opened here.  See above.
1979          */
1980 
1981         cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
1982         if (cerror)
1983                 SMBVDEBUG("error %d closing %s\\%s\n",
1984                     cerror, dnp->n_rpath, name);
1985 
1986         /*
1987          * In the open case, the name may differ a little
1988          * from what we passed to create (case, etc.)
1989          * so call lookup to get the (opened) name.
1990          *
1991          * XXX: Could avoid this extra lookup if the
1992          * "createact" result from NT_CREATE says we
1993          * created the object.
1994          */
1995         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
1996         if (error)
1997                 goto out;
1998 
1999         /* update attr and directory cache */
2000         smbfs_attr_touchdir(dnp);
2001 
2002         error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2003         if (error)
2004                 goto out;
2005 
2006         /* XXX invalidate pages if we truncated? */
2007 
2008         /* Success! */
2009         *vpp = vp;
2010         error = 0;
2011 
2012 out:
2013         smb_credrele(&scred);
2014         smbfs_rw_exit(&dnp->r_rwlock);
2015         if (name != nm)
2016                 smbfs_name_free(name, nmlen);
2017         return (error);
2018 }
2019 
2020 /*
2021  * XXX
2022  * This op should support the new FIGNORECASE flag for case-insensitive
2023  * lookups, per PSARC 2007/244.
2024  */
2025 /* ARGSUSED */
2026 static int
2027 smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
2028         int flags)
2029 {
2030         int             error;
2031         vnode_t         *vp;
2032         smbnode_t       *np;
2033         smbnode_t       *dnp;
2034         struct smb_cred scred;
2035         /* enum smbfsstat status; */
2036         smbmntinfo_t    *smi;
2037 
2038         smi = VTOSMI(dvp);
2039 
2040         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2041                 return (EPERM);
2042 
2043         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2044                 return (EIO);
2045 
2046         dnp = VTOSMB(dvp);
2047         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2048                 return (EINTR);
2049         smb_credinit(&scred, cr);
2050 
2051         /*
2052          * Verify access to the dirctory.
2053          */
2054         error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2055         if (error)
2056                 goto out;
2057 
2058         /*
2059          * NOTE:  the darwin code gets the "vp" passed in so it looks
2060          * like the "vp" has probably been "lookup"ed by the VFS layer.
2061          * It looks like we will need to lookup the vp to check the
2062          * caches and check if the object being deleted is a directory.
2063          */
2064         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2065         if (error)
2066                 goto out;
2067 
2068         /* Never allow link/unlink directories on CIFS. */
2069         if (vp->v_type == VDIR) {
2070                 VN_RELE(vp);
2071                 error = EPERM;
2072                 goto out;
2073         }
2074 
2075         /*
2076          * Now we have the real reference count on the vnode
2077          * Do we have the file open?
2078          */
2079         np = VTOSMB(vp);
2080         mutex_enter(&np->r_statelock);
2081         if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2082                 /*
2083                  * NFS does a rename on remove here.
2084                  * Probably not applicable for SMB.
2085                  * Like Darwin, just return EBUSY.
2086                  *
2087                  * XXX: Todo - Use Trans2rename, and
2088                  * if that fails, ask the server to
2089                  * set the delete-on-close flag.
2090                  */
2091                 mutex_exit(&np->r_statelock);
2092                 error = EBUSY;
2093         } else {
2094                 smbfs_attrcache_rm_locked(np);
2095                 mutex_exit(&np->r_statelock);
2096 
2097                 error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
2098 
2099                 /*
2100                  * If the file should no longer exist, discard
2101                  * any cached attributes under this node.
2102                  */
2103                 switch (error) {
2104                 case 0:
2105                 case ENOENT:
2106                 case ENOTDIR:
2107                         smbfs_attrcache_prune(np);
2108                         break;
2109                 }
2110         }
2111 
2112         VN_RELE(vp);
2113 
2114 out:
2115         smb_credrele(&scred);
2116         smbfs_rw_exit(&dnp->r_rwlock);
2117 
2118         return (error);
2119 }
2120 
2121 
2122 /*
2123  * XXX
2124  * This op should support the new FIGNORECASE flag for case-insensitive
2125  * lookups, per PSARC 2007/244.
2126  */
2127 /* ARGSUSED */
2128 static int
2129 smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2130         caller_context_t *ct, int flags)
2131 {
2132         /* vnode_t              *realvp; */
2133 
2134         if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2135             curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2136                 return (EPERM);
2137 
2138         if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2139             VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2140             odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2141             ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2142                 return (EIO);
2143 
2144         return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
2145 }
2146 
2147 /*
2148  * smbfsrename does the real work of renaming in SMBFS
2149  */
2150 /* ARGSUSED */
2151 static int
2152 smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2153         caller_context_t *ct)
2154 {
2155         int             error;
2156         int             nvp_locked = 0;
2157         vnode_t         *nvp = NULL;
2158         vnode_t         *ovp = NULL;
2159         smbnode_t       *onp;
2160         smbnode_t       *nnp;
2161         smbnode_t       *odnp;
2162         smbnode_t       *ndnp;
2163         struct smb_cred scred;
2164         /* enum smbfsstat       status; */
2165 
2166         ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2167 
2168         if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2169             strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2170                 return (EINVAL);
2171 
2172         /*
2173          * Check that everything is on the same filesystem.
2174          * vn_rename checks the fsid's, but in case we don't
2175          * fill those in correctly, check here too.
2176          */
2177         if (odvp->v_vfsp != ndvp->v_vfsp)
2178                 return (EXDEV);
2179 
2180         odnp = VTOSMB(odvp);
2181         ndnp = VTOSMB(ndvp);
2182 
2183         /*
2184          * Avoid deadlock here on old vs new directory nodes
2185          * by always taking the locks in order of address.
2186          * The order is arbitrary, but must be consistent.
2187          */
2188         if (odnp < ndnp) {
2189                 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2190                     SMBINTR(odvp)))
2191                         return (EINTR);
2192                 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2193                     SMBINTR(ndvp))) {
2194                         smbfs_rw_exit(&odnp->r_rwlock);
2195                         return (EINTR);
2196                 }
2197         } else {
2198                 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2199                     SMBINTR(ndvp)))
2200                         return (EINTR);
2201                 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2202                     SMBINTR(odvp))) {
2203                         smbfs_rw_exit(&ndnp->r_rwlock);
2204                         return (EINTR);
2205                 }
2206         }
2207         smb_credinit(&scred, cr);
2208         /*
2209          * No returns after this point (goto out)
2210          */
2211 
2212         /*
2213          * Need write access on source and target.
2214          * Server takes care of most checks.
2215          */
2216         error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2217         if (error)
2218                 goto out;
2219         if (odvp != ndvp) {
2220                 error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2221                 if (error)
2222                         goto out;
2223         }
2224 
2225         /*
2226          * Lookup the source name.  Must already exist.
2227          */
2228         error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2229         if (error)
2230                 goto out;
2231 
2232         /*
2233          * Lookup the target file.  If it exists, it needs to be
2234          * checked to see whether it is a mount point and whether
2235          * it is active (open).
2236          */
2237         error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
2238         if (!error) {
2239                 /*
2240                  * Target (nvp) already exists.  Check that it
2241                  * has the same type as the source.  The server
2242                  * will check this also, (and more reliably) but
2243                  * this lets us return the correct error codes.
2244                  */
2245                 if (ovp->v_type == VDIR) {
2246                         if (nvp->v_type != VDIR) {
2247                                 error = ENOTDIR;
2248                                 goto out;
2249                         }
2250                 } else {
2251                         if (nvp->v_type == VDIR) {
2252                                 error = EISDIR;
2253                                 goto out;
2254                         }
2255                 }
2256 
2257                 /*
2258                  * POSIX dictates that when the source and target
2259                  * entries refer to the same file object, rename
2260                  * must do nothing and exit without error.
2261                  */
2262                 if (ovp == nvp) {
2263                         error = 0;
2264                         goto out;
2265                 }
2266 
2267                 /*
2268                  * Also must ensure the target is not a mount point,
2269                  * and keep mount/umount away until we're done.
2270                  */
2271                 if (vn_vfsrlock(nvp)) {
2272                         error = EBUSY;
2273                         goto out;
2274                 }
2275                 nvp_locked = 1;
2276                 if (vn_mountedvfs(nvp) != NULL) {
2277                         error = EBUSY;
2278                         goto out;
2279                 }
2280 
2281                 /*
2282                  * CIFS gives a SHARING_VIOLATION error when
2283                  * trying to rename onto an exising object,
2284                  * so try to remove the target first.
2285                  * (Only for files, not directories.)
2286                  */
2287                 if (nvp->v_type == VDIR) {
2288                         error = EEXIST;
2289                         goto out;
2290                 }
2291 
2292                 /*
2293                  * Nodes that are "not active" here have v_count=2
2294                  * because vn_renameat (our caller) did a lookup on
2295                  * both the source and target before this call.
2296                  * Otherwise this similar to smbfs_remove.
2297                  */
2298                 nnp = VTOSMB(nvp);
2299                 mutex_enter(&nnp->r_statelock);
2300                 if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) {
2301                         /*
2302                          * The target file exists, is not the same as
2303                          * the source file, and is active.  Other FS
2304                          * implementations unlink the target here.
2305                          * For SMB, we don't assume we can remove an
2306                          * open file.  Return an error instead.
2307                          */
2308                         mutex_exit(&nnp->r_statelock);
2309                         error = EBUSY;
2310                         goto out;
2311                 }
2312 
2313                 /*
2314                  * Target file is not active. Try to remove it.
2315                  */
2316                 smbfs_attrcache_rm_locked(nnp);
2317                 mutex_exit(&nnp->r_statelock);
2318 
2319                 error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
2320 
2321                 /*
2322                  * Similar to smbfs_remove
2323                  */
2324                 switch (error) {
2325                 case 0:
2326                 case ENOENT:
2327                 case ENOTDIR:
2328                         smbfs_attrcache_prune(nnp);
2329                         break;
2330                 }
2331 
2332                 if (error)
2333                         goto out;
2334                 /*
2335                  * OK, removed the target file.  Continue as if
2336                  * lookup target had failed (nvp == NULL).
2337                  */
2338                 vn_vfsunlock(nvp);
2339                 nvp_locked = 0;
2340                 VN_RELE(nvp);
2341                 nvp = NULL;
2342         } /* nvp */
2343 
2344         onp = VTOSMB(ovp);
2345         smbfs_attrcache_remove(onp);
2346 
2347         error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
2348 
2349         /*
2350          * If the old name should no longer exist,
2351          * discard any cached attributes under it.
2352          */
2353         if (error == 0)
2354                 smbfs_attrcache_prune(onp);
2355 
2356 out:
2357         if (nvp) {
2358                 if (nvp_locked)
2359                         vn_vfsunlock(nvp);
2360                 VN_RELE(nvp);
2361         }
2362         if (ovp)
2363                 VN_RELE(ovp);
2364 
2365         smb_credrele(&scred);
2366         smbfs_rw_exit(&odnp->r_rwlock);
2367         smbfs_rw_exit(&ndnp->r_rwlock);
2368 
2369         return (error);
2370 }
2371 
2372 /*
2373  * XXX
2374  * vsecattr_t is new to build 77, and we need to eventually support
2375  * it in order to create an ACL when an object is created.
2376  *
2377  * This op should support the new FIGNORECASE flag for case-insensitive
2378  * lookups, per PSARC 2007/244.
2379  */
2380 /* ARGSUSED */
2381 static int
2382 smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2383         cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2384 {
2385         vnode_t         *vp;
2386         struct smbnode  *dnp = VTOSMB(dvp);
2387         struct smbmntinfo *smi = VTOSMI(dvp);
2388         struct smb_cred scred;
2389         struct smbfattr fattr;
2390         const char              *name = (const char *) nm;
2391         int             nmlen = strlen(name);
2392         int             error, hiderr;
2393 
2394         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2395                 return (EPERM);
2396 
2397         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2398                 return (EIO);
2399 
2400         if ((nmlen == 1 && name[0] == '.') ||
2401             (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2402                 return (EEXIST);
2403 
2404         /* Only plain files are allowed in V_XATTRDIR. */
2405         if (dvp->v_flag & V_XATTRDIR)
2406                 return (EINVAL);
2407 
2408         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2409                 return (EINTR);
2410         smb_credinit(&scred, cr);
2411 
2412         /*
2413          * XXX: Do we need r_lkserlock too?
2414          * No use of any shared fid or fctx...
2415          */
2416 
2417         /*
2418          * Require write access in the containing directory.
2419          */
2420         error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2421         if (error)
2422                 goto out;
2423 
2424         error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2425         if (error)
2426                 goto out;
2427 
2428         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2429         if (error)
2430                 goto out;
2431 
2432         smbfs_attr_touchdir(dnp);
2433 
2434         error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2435         if (error)
2436                 goto out;
2437 
2438         if (name[0] == '.')
2439                 if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2440                         SMBVDEBUG("hide failure %d\n", hiderr);
2441 
2442         /* Success! */
2443         *vpp = vp;
2444         error = 0;
2445 out:
2446         smb_credrele(&scred);
2447         smbfs_rw_exit(&dnp->r_rwlock);
2448 
2449         if (name != nm)
2450                 smbfs_name_free(name, nmlen);
2451 
2452         return (error);
2453 }
2454 
2455 /*
2456  * XXX
2457  * This op should support the new FIGNORECASE flag for case-insensitive
2458  * lookups, per PSARC 2007/244.
2459  */
2460 /* ARGSUSED */
2461 static int
2462 smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2463         caller_context_t *ct, int flags)
2464 {
2465         vnode_t         *vp = NULL;
2466         int             vp_locked = 0;
2467         struct smbmntinfo *smi = VTOSMI(dvp);
2468         struct smbnode  *dnp = VTOSMB(dvp);
2469         struct smbnode  *np;
2470         struct smb_cred scred;
2471         int             error;
2472 
2473         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2474                 return (EPERM);
2475 
2476         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2477                 return (EIO);
2478 
2479         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2480                 return (EINTR);
2481         smb_credinit(&scred, cr);
2482 
2483         /*
2484          * Require w/x access in the containing directory.
2485          * Server handles all other access checks.
2486          */
2487         error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2488         if (error)
2489                 goto out;
2490 
2491         /*
2492          * First lookup the entry to be removed.
2493          */
2494         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2495         if (error)
2496                 goto out;
2497         np = VTOSMB(vp);
2498 
2499         /*
2500          * Disallow rmdir of "." or current dir, or the FS root.
2501          * Also make sure it's a directory, not a mount point,
2502          * and lock to keep mount/umount away until we're done.
2503          */
2504         if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2505                 error = EINVAL;
2506                 goto out;
2507         }
2508         if (vp->v_type != VDIR) {
2509                 error = ENOTDIR;
2510                 goto out;
2511         }
2512         if (vn_vfsrlock(vp)) {
2513                 error = EBUSY;
2514                 goto out;
2515         }
2516         vp_locked = 1;
2517         if (vn_mountedvfs(vp) != NULL) {
2518                 error = EBUSY;
2519                 goto out;
2520         }
2521 
2522         smbfs_attrcache_remove(np);
2523         error = smbfs_smb_rmdir(np, &scred);
2524 
2525         /*
2526          * Similar to smbfs_remove
2527          */
2528         switch (error) {
2529         case 0:
2530         case ENOENT:
2531         case ENOTDIR:
2532                 smbfs_attrcache_prune(np);
2533                 break;
2534         }
2535 
2536         if (error)
2537                 goto out;
2538 
2539         mutex_enter(&np->r_statelock);
2540         dnp->n_flag |= NMODIFIED;
2541         mutex_exit(&np->r_statelock);
2542         smbfs_attr_touchdir(dnp);
2543         smbfs_rmhash(np);
2544 
2545 out:
2546         if (vp) {
2547                 if (vp_locked)
2548                         vn_vfsunlock(vp);
2549                 VN_RELE(vp);
2550         }
2551         smb_credrele(&scred);
2552         smbfs_rw_exit(&dnp->r_rwlock);
2553 
2554         return (error);
2555 }
2556 
2557 
2558 /* ARGSUSED */
2559 static int
2560 smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2561         caller_context_t *ct, int flags)
2562 {
2563         struct smbnode  *np = VTOSMB(vp);
2564         int             error = 0;
2565         smbmntinfo_t    *smi;
2566 
2567         smi = VTOSMI(vp);
2568 
2569         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2570                 return (EIO);
2571 
2572         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2573                 return (EIO);
2574 
2575         /*
2576          * Require read access in the directory.
2577          */
2578         error = smbfs_access(vp, VREAD, 0, cr, ct);
2579         if (error)
2580                 return (error);
2581 
2582         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2583 
2584         /*
2585          * XXX: Todo readdir cache here
2586          * Note: NFS code is just below this.
2587          *
2588          * I am serializing the entire readdir opreation
2589          * now since we have not yet implemented readdir
2590          * cache. This fix needs to be revisited once
2591          * we implement readdir cache.
2592          */
2593         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2594                 return (EINTR);
2595 
2596         error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2597 
2598         smbfs_rw_exit(&np->r_lkserlock);
2599 
2600         return (error);
2601 }
2602 
2603 /* ARGSUSED */
2604 static int
2605 smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2606         caller_context_t *ct)
2607 {
2608         /*
2609          * Note: "limit" tells the SMB-level FindFirst/FindNext
2610          * functions how many directory entries to request in
2611          * each OtW call.  It needs to be large enough so that
2612          * we don't make lots of tiny OtW requests, but there's
2613          * no point making it larger than the maximum number of
2614          * OtW entries that would fit in a maximum sized trans2
2615          * response (64k / 48).  Beyond that, it's just tuning.
2616          * WinNT used 512, Win2k used 1366.  We use 1000.
2617          */
2618         static const int limit = 1000;
2619         /* Largest possible dirent size. */
2620         static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2621         struct smb_cred scred;
2622         vnode_t         *newvp;
2623         struct smbnode  *np = VTOSMB(vp);
2624         struct smbfs_fctx *ctx;
2625         struct dirent64 *dp;
2626         ssize_t         save_resid;
2627         offset_t        save_offset; /* 64 bits */
2628         int             offset; /* yes, 32 bits */
2629         int             nmlen, error;
2630         ushort_t        reclen;
2631 
2632         ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2633 
2634         /* Make sure we serialize for n_dirseq use. */
2635         ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2636 
2637         /*
2638          * Make sure smbfs_open filled in n_dirseq
2639          */
2640         if (np->n_dirseq == NULL)
2641                 return (EBADF);
2642 
2643         /* Check for overflow of (32-bit) directory offset. */
2644         if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2645             (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2646                 return (EINVAL);
2647 
2648         /* Require space for at least one dirent. */
2649         if (uio->uio_resid < dbufsiz)
2650                 return (EINVAL);
2651 
2652         SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2653         smb_credinit(&scred, cr);
2654         dp = kmem_alloc(dbufsiz, KM_SLEEP);
2655 
2656         save_resid = uio->uio_resid;
2657         save_offset = uio->uio_loffset;
2658         offset = uio->uio_offset;
2659         SMBVDEBUG("in: offset=%d, resid=%d\n",
2660             (int)uio->uio_offset, (int)uio->uio_resid);
2661         error = 0;
2662 
2663         /*
2664          * Generate the "." and ".." entries here so we can
2665          * (1) make sure they appear (but only once), and
2666          * (2) deal with getting their I numbers which the
2667          * findnext below does only for normal names.
2668          */
2669         while (offset < FIRST_DIROFS) {
2670                 /*
2671                  * Tricky bit filling in the first two:
2672                  * offset 0 is ".", offset 1 is ".."
2673                  * so strlen of these is offset+1.
2674                  */
2675                 reclen = DIRENT64_RECLEN(offset + 1);
2676                 if (uio->uio_resid < reclen)
2677                         goto out;
2678                 bzero(dp, reclen);
2679                 dp->d_reclen = reclen;
2680                 dp->d_name[0] = '.';
2681                 dp->d_name[1] = '.';
2682                 dp->d_name[offset + 1] = '\0';
2683                 /*
2684                  * Want the real I-numbers for the "." and ".."
2685                  * entries.  For these two names, we know that
2686                  * smbfslookup can get the nodes efficiently.
2687                  */
2688                 error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2689                 if (error) {
2690                         dp->d_ino = np->n_ino + offset; /* fiction */
2691                 } else {
2692                         dp->d_ino = VTOSMB(newvp)->n_ino;
2693                         VN_RELE(newvp);
2694                 }
2695                 /*
2696                  * Note: d_off is the offset that a user-level program
2697                  * should seek to for reading the NEXT directory entry.
2698                  * See libc: readdir, telldir, seekdir
2699                  */
2700                 dp->d_off = offset + 1;
2701                 error = uiomove(dp, reclen, UIO_READ, uio);
2702                 if (error)
2703                         goto out;
2704                 /*
2705                  * Note: uiomove updates uio->uio_offset,
2706                  * but we want it to be our "cookie" value,
2707                  * which just counts dirents ignoring size.
2708                  */
2709                 uio->uio_offset = ++offset;
2710         }
2711 
2712         /*
2713          * If there was a backward seek, we have to reopen.
2714          */
2715         if (offset < np->n_dirofs) {
2716                 SMBVDEBUG("Reopening search %d:%d\n",
2717                     offset, np->n_dirofs);
2718                 error = smbfs_smb_findopen(np, "*", 1,
2719                     SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2720                     &scred, &ctx);
2721                 if (error) {
2722                         SMBVDEBUG("can not open search, error = %d", error);
2723                         goto out;
2724                 }
2725                 /* free the old one */
2726                 (void) smbfs_smb_findclose(np->n_dirseq, &scred);
2727                 /* save the new one */
2728                 np->n_dirseq = ctx;
2729                 np->n_dirofs = FIRST_DIROFS;
2730         } else {
2731                 ctx = np->n_dirseq;
2732         }
2733 
2734         /*
2735          * Skip entries before the requested offset.
2736          */
2737         while (np->n_dirofs < offset) {
2738                 error = smbfs_smb_findnext(ctx, limit, &scred);
2739                 if (error != 0)
2740                         goto out;
2741                 np->n_dirofs++;
2742         }
2743 
2744         /*
2745          * While there's room in the caller's buffer:
2746          *      get a directory entry from SMB,
2747          *      convert to a dirent, copyout.
2748          * We stop when there is no longer room for a
2749          * maximum sized dirent because we must decide
2750          * before we know anything about the next entry.
2751          */
2752         while (uio->uio_resid >= dbufsiz) {
2753                 error = smbfs_smb_findnext(ctx, limit, &scred);
2754                 if (error != 0)
2755                         goto out;
2756                 np->n_dirofs++;
2757 
2758                 /* Sanity check the name length. */
2759                 nmlen = ctx->f_nmlen;
2760                 if (nmlen > SMB_MAXFNAMELEN) {
2761                         nmlen = SMB_MAXFNAMELEN;
2762                         SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2763                 }
2764                 if (smbfs_fastlookup) {
2765                         /* See comment at smbfs_fastlookup above. */
2766                         if (smbfs_nget(vp, ctx->f_name, nmlen,
2767                             &ctx->f_attr, &newvp) == 0)
2768                                 VN_RELE(newvp);
2769                 }
2770 
2771                 reclen = DIRENT64_RECLEN(nmlen);
2772                 bzero(dp, reclen);
2773                 dp->d_reclen = reclen;
2774                 bcopy(ctx->f_name, dp->d_name, nmlen);
2775                 dp->d_name[nmlen] = '\0';
2776                 dp->d_ino = ctx->f_inum;
2777                 dp->d_off = offset + 1;      /* See d_off comment above */
2778                 error = uiomove(dp, reclen, UIO_READ, uio);
2779                 if (error)
2780                         goto out;
2781                 /* See comment re. uio_offset above. */
2782                 uio->uio_offset = ++offset;
2783         }
2784 
2785 out:
2786         /*
2787          * When we come to the end of a directory, the
2788          * SMB-level functions return ENOENT, but the
2789          * caller is not expecting an error return.
2790          *
2791          * Also note that we must delay the call to
2792          * smbfs_smb_findclose(np->n_dirseq, ...)
2793          * until smbfs_close so that all reads at the
2794          * end of the directory will return no data.
2795          */
2796         if (error == ENOENT) {
2797                 error = 0;
2798                 if (eofp)
2799                         *eofp = 1;
2800         }
2801         /*
2802          * If we encountered an error (i.e. "access denied")
2803          * from the FindFirst call, we will have copied out
2804          * the "." and ".." entries leaving offset == 2.
2805          * In that case, restore the original offset/resid
2806          * so the caller gets no data with the error.
2807          */
2808         if (error != 0 && offset == FIRST_DIROFS) {
2809                 uio->uio_loffset = save_offset;
2810                 uio->uio_resid = save_resid;
2811         }
2812         SMBVDEBUG("out: offset=%d, resid=%d\n",
2813             (int)uio->uio_offset, (int)uio->uio_resid);
2814 
2815         kmem_free(dp, dbufsiz);
2816         smb_credrele(&scred);
2817         return (error);
2818 }
2819 
2820 
2821 /*
2822  * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2823  * are optional functions that are called by:
2824  *    getdents, before/after VOP_READDIR
2825  *    pread, before/after ... VOP_READ
2826  *    pwrite, before/after ... VOP_WRITE
2827  *    (other places)
2828  *
2829  * Careful here: None of the above check for any
2830  * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2831  * In fact, the return value from _rwlock is NOT
2832  * an error code, but V_WRITELOCK_TRUE / _FALSE.
2833  *
2834  * Therefore, it's up to _this_ code to make sure
2835  * the lock state remains balanced, which means
2836  * we can't "bail out" on interrupts, etc.
2837  */
2838 
2839 /* ARGSUSED2 */
2840 static int
2841 smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2842 {
2843         smbnode_t       *np = VTOSMB(vp);
2844 
2845         if (!write_lock) {
2846                 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2847                 return (V_WRITELOCK_FALSE);
2848         }
2849 
2850 
2851         (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2852         return (V_WRITELOCK_TRUE);
2853 }
2854 
2855 /* ARGSUSED */
2856 static void
2857 smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2858 {
2859         smbnode_t       *np = VTOSMB(vp);
2860 
2861         smbfs_rw_exit(&np->r_rwlock);
2862 }
2863 
2864 
2865 /* ARGSUSED */
2866 static int
2867 smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2868 {
2869         smbmntinfo_t    *smi;
2870 
2871         smi = VTOSMI(vp);
2872 
2873         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2874                 return (EPERM);
2875 
2876         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2877                 return (EIO);
2878 
2879         /*
2880          * Because we stuff the readdir cookie into the offset field
2881          * someone may attempt to do an lseek with the cookie which
2882          * we want to succeed.
2883          */
2884         if (vp->v_type == VDIR)
2885                 return (0);
2886 
2887         /* Like NFS3, just check for 63-bit overflow. */
2888         if (*noffp < 0)
2889                 return (EINVAL);
2890 
2891         return (0);
2892 }
2893 
2894 
2895 /*
2896  * XXX
2897  * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2898  */
2899 static int
2900 smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2901         offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2902         caller_context_t *ct)
2903 {
2904         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2905                 return (EIO);
2906 
2907         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2908                 return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2909         else
2910                 return (ENOSYS);
2911 }
2912 
2913 /*
2914  * Free storage space associated with the specified vnode.  The portion
2915  * to be freed is specified by bfp->l_start and bfp->l_len (already
2916  * normalized to a "whence" of 0).
2917  *
2918  * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2919  */
2920 /* ARGSUSED */
2921 static int
2922 smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2923         offset_t offset, cred_t *cr, caller_context_t *ct)
2924 {
2925         int             error;
2926         smbmntinfo_t    *smi;
2927 
2928         smi = VTOSMI(vp);
2929 
2930         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2931                 return (EIO);
2932 
2933         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2934                 return (EIO);
2935 
2936         /* Caller (fcntl) has checked v_type */
2937         ASSERT(vp->v_type == VREG);
2938         if (cmd != F_FREESP)
2939                 return (EINVAL);
2940 
2941         /*
2942          * Like NFS3, no 32-bit offset checks here.
2943          * Our SMB layer takes care to return EFBIG
2944          * when it has to fallback to a 32-bit call.
2945          */
2946 
2947         error = convoff(vp, bfp, 0, offset);
2948         if (!error) {
2949                 ASSERT(bfp->l_start >= 0);
2950                 if (bfp->l_len == 0) {
2951                         struct vattr va;
2952 
2953                         /*
2954                          * ftruncate should not change the ctime and
2955                          * mtime if we truncate the file to its
2956                          * previous size.
2957                          */
2958                         va.va_mask = AT_SIZE;
2959                         error = smbfsgetattr(vp, &va, cr);
2960                         if (error || va.va_size == bfp->l_start)
2961                                 return (error);
2962                         va.va_mask = AT_SIZE;
2963                         va.va_size = bfp->l_start;
2964                         error = smbfssetattr(vp, &va, 0, cr);
2965                 } else
2966                         error = EINVAL;
2967         }
2968 
2969         return (error);
2970 }
2971 
2972 /* ARGSUSED */
2973 static int
2974 smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
2975         caller_context_t *ct)
2976 {
2977         vfs_t *vfs;
2978         smbmntinfo_t *smi;
2979         struct smb_share *ssp;
2980 
2981         vfs = vp->v_vfsp;
2982         smi = VFTOSMI(vfs);
2983 
2984         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2985                 return (EIO);
2986 
2987         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2988                 return (EIO);
2989 
2990         switch (cmd) {
2991         case _PC_FILESIZEBITS:
2992                 ssp = smi->smi_share;
2993                 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
2994                         *valp = 64;
2995                 else
2996                         *valp = 32;
2997                 break;
2998 
2999         case _PC_LINK_MAX:
3000                 /* We only ever report one link to an object */
3001                 *valp = 1;
3002                 break;
3003 
3004         case _PC_ACL_ENABLED:
3005                 /*
3006                  * Always indicate that ACLs are enabled and
3007                  * that we support ACE_T format, otherwise
3008                  * libsec will ask for ACLENT_T format data
3009                  * which we don't support.
3010                  */
3011                 *valp = _ACL_ACE_ENABLED;
3012                 break;
3013 
3014         case _PC_SYMLINK_MAX:   /* No symlinks until we do Unix extensions */
3015                 *valp = 0;
3016                 break;
3017 
3018         case _PC_XATTR_EXISTS:
3019                 if (vfs->vfs_flag & VFS_XATTR) {
3020                         *valp = smbfs_xa_exists(vp, cr);
3021                         break;
3022                 }
3023                 return (EINVAL);
3024 
3025         case _PC_TIMESTAMP_RESOLUTION:
3026                 /*
3027                  * Windows times are tenths of microseconds
3028                  * (multiples of 100 nanoseconds).
3029                  */
3030                 *valp = 100L;
3031                 break;
3032 
3033         default:
3034                 return (fs_pathconf(vp, cmd, valp, cr, ct));
3035         }
3036         return (0);
3037 }
3038 
3039 /* ARGSUSED */
3040 static int
3041 smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3042         caller_context_t *ct)
3043 {
3044         vfs_t *vfsp;
3045         smbmntinfo_t *smi;
3046         int     error;
3047         uint_t  mask;
3048 
3049         vfsp = vp->v_vfsp;
3050         smi = VFTOSMI(vfsp);
3051 
3052         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3053                 return (EIO);
3054 
3055         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3056                 return (EIO);
3057 
3058         /*
3059          * Our _pathconf indicates _ACL_ACE_ENABLED,
3060          * so we should only see VSA_ACE, etc here.
3061          * Note: vn_create asks for VSA_DFACLCNT,
3062          * and it expects ENOSYS and empty data.
3063          */
3064         mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3065             VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3066         if (mask == 0)
3067                 return (ENOSYS);
3068 
3069         if (smi->smi_flags & SMI_ACL)
3070                 error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3071         else
3072                 error = ENOSYS;
3073 
3074         if (error == ENOSYS)
3075                 error = fs_fab_acl(vp, vsa, flag, cr, ct);
3076 
3077         return (error);
3078 }
3079 
3080 /* ARGSUSED */
3081 static int
3082 smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3083         caller_context_t *ct)
3084 {
3085         vfs_t *vfsp;
3086         smbmntinfo_t *smi;
3087         int     error;
3088         uint_t  mask;
3089 
3090         vfsp = vp->v_vfsp;
3091         smi = VFTOSMI(vfsp);
3092 
3093         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3094                 return (EIO);
3095 
3096         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3097                 return (EIO);
3098 
3099         /*
3100          * Our _pathconf indicates _ACL_ACE_ENABLED,
3101          * so we should only see VSA_ACE, etc here.
3102          */
3103         mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3104         if (mask == 0)
3105                 return (ENOSYS);
3106 
3107         if (vfsp->vfs_flag & VFS_RDONLY)
3108                 return (EROFS);
3109 
3110         /*
3111          * Allow only the mount owner to do this.
3112          * See comments at smbfs_access_rwx.
3113          */
3114         error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3115         if (error != 0)
3116                 return (error);
3117 
3118         if (smi->smi_flags & SMI_ACL)
3119                 error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3120         else
3121                 error = ENOSYS;
3122 
3123         return (error);
3124 }
3125 
3126 
3127 /*
3128  * XXX
3129  * This op should eventually support PSARC 2007/268.
3130  */
3131 static int
3132 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3133         caller_context_t *ct)
3134 {
3135         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3136                 return (EIO);
3137 
3138         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3139                 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3140         else
3141                 return (ENOSYS);
3142 }
3143 
3144 
3145 
3146 
3147 static int smbfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
3148         size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
3149         caller_context_t *ct) {
3150     smbnode_t *np;
3151     smbmntinfo_t *smi;
3152     struct vattr va;
3153     segvn_crargs_t vn_a;
3154     int error;
3155 
3156     np = VTOSMB(vp);
3157     smi = VTOSMI(vp);
3158 
3159     if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3160         return (EIO);
3161 
3162     if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3163         return (EIO);
3164 
3165     if (vp->v_flag & VNOMAP || vp->v_flag & VNOCACHE)
3166         return (EAGAIN);
3167 
3168     if (vp->v_type != VREG)
3169         return (ENODEV);
3170 
3171     va.va_mask = AT_ALL;
3172 
3173     if (error = smbfsgetattr(vp, &va, cr))
3174         return (error);
3175 
3176     if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
3177         return (EINTR);
3178 
3179     if (MANDLOCK(vp, va.va_mode)) {
3180         error = EAGAIN;
3181         goto out;
3182     }
3183 
3184     as_rangelock(as);
3185     error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
3186 
3187     if (error != 0) {
3188         as_rangeunlock(as);
3189         goto out;
3190     }
3191 
3192     vn_a.vp = vp;
3193     vn_a.offset = (u_offset_t) off;
3194     vn_a.type = flags & MAP_TYPE;
3195     vn_a.prot = (uchar_t) prot;
3196     vn_a.maxprot = (uchar_t) maxprot;
3197     vn_a.cred = cr;
3198     vn_a.amp = NULL;
3199     vn_a.flags = flags & ~MAP_TYPE;
3200     vn_a.szc = 0;
3201     vn_a.lgrp_mem_policy_flags = 0;
3202 
3203     error = as_map(as, *addrp, len, segvn_create, &vn_a);
3204 
3205     as_rangeunlock(as);
3206 
3207 out:
3208     smbfs_rw_exit(&np->r_lkserlock);
3209 
3210     return (error);
3211 }
3212 
3213 static int smbfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
3214         size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
3215         caller_context_t *ct) {
3216     atomic_add_long((ulong_t *) & VTOSMB(vp)->r_mapcnt, btopr(len));
3217     return (0);
3218 }
3219 
3220 static int smbfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
3221         size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
3222         caller_context_t *ct) {
3223     atomic_add_long((ulong_t *) & VTOSMB(vp)->r_mapcnt, -btopr(len));
3224     return (0);
3225 }
3226 
3227 static int smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags,
3228         cred_t *cr, caller_context_t *ct) {
3229 
3230     smbnode_t *np;
3231     size_t io_len;
3232     u_offset_t io_off;
3233     u_offset_t eoff;
3234     int error = 0;
3235     page_t *pp;
3236 
3237     np = VTOSMB(vp);
3238 
3239     if (len == 0) {
3240         error = pvn_vplist_dirty(vp, off, smbfs_putapage, flags, cr);
3241     } else {
3242 
3243         eoff = off + len;
3244 
3245         mutex_enter(&np->r_statelock);
3246         if (eoff > np->r_size)
3247             eoff = np->r_size;
3248         mutex_exit(&np->r_statelock);
3249 
3250         for (io_off = off; io_off < eoff; io_off += io_len) {
3251             if ((flags & B_INVAL) || (flags & B_ASYNC) == 0) {
3252                 pp = page_lookup(vp, io_off,
3253                         (flags & (B_INVAL | B_FREE) ? SE_EXCL : SE_SHARED));
3254             } else {
3255                 pp = page_lookup_nowait(vp, io_off,
3256                         (flags & B_FREE) ? SE_EXCL : SE_SHARED);
3257             }
3258 
3259             if (pp == NULL || !pvn_getdirty(pp, flags))
3260                 io_len = PAGESIZE;
3261             else {
3262                 error = smbfs_putapage(vp, pp, &io_off, &io_len, flags, cr);
3263             }
3264         }
3265 
3266     }
3267 
3268     return (error);
3269 }
3270 
3271 static int smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
3272         int flags, cred_t *cr) {
3273 
3274     struct smb_cred scred;
3275     smbnode_t *np;
3276     smbmntinfo_t *smi;
3277     smb_share_t *ssp;
3278     uio_t uio;
3279     iovec_t uiov;
3280 
3281     u_offset_t off;
3282     size_t len;
3283     int error, timo;
3284 
3285     np = VTOSMB(vp);
3286     smi = VTOSMI(vp);
3287     ssp = smi->smi_share;
3288 
3289     off = pp->p_offset;
3290     len = PAGESIZE;
3291 
3292     if (off >= np->r_size) {
3293         error = 0;
3294         goto out;
3295     } else if (off + len > np->r_size) {
3296         int npages = btopr(np->r_size - off);
3297         page_t *trunc;
3298 
3299         page_list_break(&pp, &trunc, npages);
3300         if (trunc)
3301             pvn_write_done(trunc, flags);
3302         len = np->r_size - off;
3303     }
3304 
3305     timo = smb_timo_write;
3306 
3307     if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
3308         return (EINTR);
3309     smb_credinit(&scred, cr);
3310 
3311     if (np->n_vcgenid != ssp->ss_vcgenid)
3312         error = ESTALE;
3313     else {
3314         uiov.iov_base = 0;
3315         uiov.iov_len = 0;
3316         uio.uio_iov = &uiov;
3317         uio.uio_iovcnt = 1;
3318         uio.uio_loffset = off;
3319         uio.uio_resid = len;
3320         uio.uio_segflg = UIO_SYSSPACE;
3321         uio.uio_llimit = MAXOFFSET_T;
3322         error = up_mapin(&uio, pp);
3323         if (error == 0) {
3324             error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, &uio, &scred, timo);
3325             if (error == 0) {
3326                 mutex_enter(&np->r_statelock);
3327                 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
3328                 mutex_exit(&np->r_statelock);
3329                 (void) smbfs_smb_flush(np, &scred);
3330             }
3331             up_mapout(&uio, pp);
3332         }
3333     }
3334     smb_credrele(&scred);
3335     smbfs_rw_exit(&np->r_lkserlock);
3336 
3337 out:
3338     pvn_write_done(pp, B_WRITE | flags);
3339 
3340     return (error);
3341 }
3342 
3343 static int up_mapin(uio_t *uiop, page_t *pp) {
3344     u_offset_t off;
3345     size_t size;
3346     pgcnt_t npages;
3347     caddr_t kaddr;
3348 
3349     off = (uintptr_t) uiop->uio_loffset & PAGEOFFSET;
3350     size = P2ROUNDUP(uiop->uio_resid + off, PAGESIZE);
3351     npages = btop(size);
3352 
3353     if (npages == 1 && kpm_enable) {
3354         kaddr = hat_kpm_mapin(pp, NULL);
3355         uiop->uio_iov->iov_base = kaddr;
3356         uiop->uio_iov->iov_len = PAGESIZE;
3357         return (0);
3358     }
3359     return (EFAULT);
3360 }
3361 
3362 static int up_mapout(uio_t *uiop, page_t *pp) {
3363     u_offset_t off;
3364     size_t size;
3365     pgcnt_t npages;
3366     caddr_t kaddr;
3367 
3368     kaddr = uiop->uio_iov->iov_base;
3369     off = (uintptr_t) kaddr & PAGEOFFSET;
3370     size = P2ROUNDUP(uiop->uio_iov->iov_len + off, PAGESIZE);
3371     npages = btop(size);
3372 
3373     if (npages == 1 && kpm_enable) {
3374         kaddr = (caddr_t) ((uintptr_t) kaddr & MMU_PAGEMASK);
3375         hat_kpm_mapout(pp, NULL, kaddr);
3376         uiop->uio_iov->iov_base = 0;
3377         uiop->uio_iov->iov_len = 0;
3378         return (0);
3379     }
3380     return (EFAULT);
3381 }
3382 
3383 static int smbfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
3384         page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
3385         enum seg_rw rw, cred_t *cr, caller_context_t *ct) {
3386     int error;
3387     smbnode_t *np;
3388 
3389     np = VTOSMB(vp);
3390 
3391     mutex_enter(&np->r_statelock);
3392     if (off + len > np->r_size + PAGEOFFSET && seg != segkmap) {
3393         mutex_exit(&np->r_statelock);
3394         return (EFAULT);
3395     }
3396     mutex_exit(&np->r_statelock);
3397 
3398     if (len <= PAGESIZE) {
3399         error = smbfs_getapage(vp, off, len, protp, pl, plsz, seg, addr, rw,
3400                 cr);
3401     } else {
3402         error = pvn_getpages(smbfs_getapage, vp, off, len, protp, pl, plsz, seg,
3403                 addr, rw, cr);
3404     }
3405     return (error);
3406 }
3407 
3408 static int smbfs_getapage(vnode_t *vp, u_offset_t off, size_t len,
3409         uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
3410         enum seg_rw rw, cred_t *cr) {
3411 
3412     smbnode_t *np;
3413     smbmntinfo_t *smi;
3414     smb_share_t *ssp;
3415     smb_cred_t scred;
3416 
3417     page_t *pagefound, *pp;
3418     uio_t uio;
3419     iovec_t uiov;
3420 
3421     int error = 0, timo;
3422 
3423     np = VTOSMB(vp);
3424     smi = VTOSMI(vp);
3425     ssp = smi->smi_share;
3426 
3427     if (len > PAGESIZE)
3428         return (EFAULT);
3429     len = PAGESIZE;
3430 
3431     if (pl == NULL)
3432         return (EFAULT);
3433 
3434     if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
3435         return EINTR;
3436 
3437     smb_credinit(&scred, cr);
3438 
3439 again:
3440     if ((pagefound = page_exists(vp, off)) == NULL) {
3441         if ((pp = page_create_va(vp, off, PAGESIZE, PG_WAIT | PG_EXCL, seg, addr)) == NULL)
3442             goto again;
3443         if (rw == S_CREATE) {
3444             goto out;
3445         } else {
3446             timo = smb_timo_read;
3447 
3448             uiov.iov_base = 0;
3449             uiov.iov_len = 0;
3450             uio.uio_iov = &uiov;
3451             uio.uio_iovcnt = 1;
3452             uio.uio_loffset = off;
3453             uio.uio_resid = len;
3454             uio.uio_segflg = UIO_SYSSPACE;
3455             uio.uio_llimit = MAXOFFSET_T;
3456             error = up_mapin(&uio, pp);
3457             if (error == 0) {
3458                 error = smb_rwuio(ssp, np->n_fid, UIO_READ, &uio, &scred, timo);
3459                 up_mapout(&uio, pp);
3460             }
3461         }
3462     } else {
3463         se_t se = rw == S_CREATE ? SE_EXCL : SE_SHARED;
3464         if ((pp = page_lookup(vp, off, se)) == NULL) {
3465             goto again;
3466         }
3467     }
3468 
3469 out:
3470     if (pp) {
3471         pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw);
3472     }
3473 
3474     smb_credrele(&scred);
3475     smbfs_rw_exit(&np->r_lkserlock);
3476 
3477     return (error);
3478 }