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