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