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