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