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